Скомпилированный запрос LINQ & DataLoadOptions ... с изюминкой! - PullRequest
6 голосов
/ 03 декабря 2009

Я знаю о методе, обсуждаемом здесь:

Решение типичных проблем с помощью скомпилированных запросов от Linq до Sql для веб-сайтов ASP.NET с высоким спросом

... но это не работает для моей ситуации, так как я получаю:

«Настройка параметров загрузки запрещена после того, как результаты возвращены из запроса.»

Я использую сценарии Codesmith PLINQO для генерации сущностей и кода менеджера, а код менеджера выглядит примерно так:

public partial class SearchManager
{       
    #region Query
    // A private class for lazy loading static compiled queries.
    private static partial class Query
    {
        internal static readonly Func<MyDataContext,IOrderedQueryable<Search>> 
            GetAll = CompiledQuery.Compile(
                (MyDataContext db) =>
                from s in db.Search
                orderby s.Name
                select s);
    } 
    #endregion


    public IQueryable<Search> GetAll()
    {
        return Query.GetAll(Context);
    }
}

Сначала я попытался добавить статические DataLoadOptions в класс Searchmanager, например:

public static readonly DataLoadOptions MyOptions = 
    (new Func<DataLoadOptions>(() =>
    {
        var option = new DataLoadOptions();
        option.LoadWith<Search>(x => x.Rule);
        return option;
    }))();

... затем предоставляя его в контекст в методе GetAll, например:

public IQueryable<Search> GetAll()
{
    Context.LoadOptions = MyOptions;
    return Query.GetAll(Context);
}

... и это дало мне ошибку, которую я заметил выше. Это потому, что запрос уже скомпилирован, и поэтому не может быть добавлено «лишних» DataLoadOptions? Если это так, как можно применить DataLoadOptions до того, как запрос будет скомпилирован?

Ответы [ 4 ]

2 голосов
/ 05 марта 2012

В свойстве setter класса DataContext есть условие, которое проверяет, есть ли у DataContext какие-либо объекты в его кэше, и значение LoadOptions НЕ равно NULL, а экземпляр LoadOptions, который вы пытаетесь установить, отличается от один уже установлен, тогда вы получите это исключение.

Альтернатива № 1. Создать новый контекст для каждого запроса (вероятно, не очень хорошая идея)
Альтернатива № 2. Вызовите метод ClearCache с помощью отражения, затем статически создайте новые LoadOptions, назначьте их в Context и, наконец, получите скомпилированный запрос.

public partial class SearchManager
{       
    #region Query
    // A private class for lazy loading static compiled queries.
    private static partial class Query
    {
        internal static readonly Func<MyDataContext,IOrderedQueryable<Search>> GetAll 
        {
            get {
                return CompiledQuery.Compile(
                    (MyDataContext db) =>
                        from s in db.Search
                        orderby s.Name
                        select s);
            }
        } 
    #endregion

    public IQueryable<Search> GetAll()
    {
        Context.ClearCache();
        Context.LoadOptions = MyOptions;
        return Query.GetAll(Context);
    }

    public static readonly DataLoadOptions MyOptions = 
        (new Func<DataLoadOptions>(() => MakeLoadOptions<Search>(x=>x.Rule)))();
}

public static class Extensions {
    public static void ClearCache(this DataContext context)
    {
        const BindingFlags FLAGS = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
        var method = context.GetType().GetMethod("ClearCache", FLAGS);
        method.Invoke(context, null);
    }

    public static DataLoadOptions MakeLoadOptions<TEntity, TResult>(this Expression<Func<TEntity,TResult>> func) {
        DataLoadOptions options = new DataLoadOptions();
        options.LoadWith(func);
        return options;
    }
}
0 голосов
/ 27 июля 2010

Вы можете установить параметры загрузки только один раз для скомпилированного запроса. Ошибка должна быть сброшена при втором вызове. Переместите присвоение в статический конструктор, и это должно решить вашу проблему.

0 голосов
/ 24 мая 2011
public IQueryable<Search> GetAll() {
     Context.LoadOptions = MyOptions;
     return Query.GetAll(Context);
 } 

Это назначение слишком поздно, если Контекст уже вернул результаты запроса. Это не имеет ничего общего с скомпилированными запросами и связано с назначением свойства LoadOptions объекта DataContext. К сожалению, такое поведение свойства LoadOptions не задокументировано в msdn.

0 голосов
/ 03 декабря 2009

Само сообщение об ошибке говорит вам, что именно не так. Вы не можете применять DataLoadOptions после того, как запрос Linq вернул результаты. Или, может быть, лучший способ сказать это заключается в следующем. Если вы хотите применить DataLoadOptions, сделайте это перед выполнением запроса. Вы не можете сделать это потом.

...