编译LINQ查询& DataLoadOptions ...扭曲!

时间:2009-12-03 08:42:10

标签: c# linq compiled-query loadoptions

我知道这里讨论的方法:

Solving common problems with Compiled Queries in Linq to Sql for high demand ASP.NET websites

...但这对我的情况不起作用,因为我得到了:

“从查询返回结果后,不允许设置加载选项。”

我使用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方法中的Context,如:

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

......这给了我上面提到的错误。这是因为查询已经编译,因此不能添加“额外”DataLoadOptions吗?如果是这样,如何在编译查询之前应用DataLoadOptions?

4 个答案:

答案 0 :(得分:2)

在DataContext类的setter属性中,有一个条件检查DataContext是否在其Cache中有任何对象,并且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;
    }
}

答案 1 :(得分:0)

错误消息本身会告诉您究竟出了什么问题。 Linq查询返回结果后,您无法应用DataLoadOptions。或者,也许更好的方式来说明如下。如果要应用DataLoadOptions,请在执行查询之前执行此操作。之后你不能这样做。

答案 2 :(得分:0)

您只能为已编译的查询设置一次加载选项。必须在第二次调用时抛出错误。将赋值移动到静态构造函数,这应该可以解决您的问题。

答案 3 :(得分:0)

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

如果Context已经返回任何查询结果,则此分配为时已晚。这与编译的查询无关,也与分配DataContext的LoadOptions属性有关。不幸的是,msdn没有记录LoadOptions属性的这种行为。