Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compiled LINQ query & DataLoadOptions... with a twist!

I know about the method discussed here:

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

... but this doesn't work for my situation as i get a :

"Setting load options is not allowed after results have been returned from a query."

I am using Codesmith PLINQO scripts to generate entities and manager code, and the manager code looks something like this:

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);
    }
}

I first tried dropping a static DataLoadOptions into the Searchmanager class like this:

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

... then providing it to the Context in the GetAll method like:

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

...and that gave me the error i noted above. Is this because the query is already compiled, and thus can't have "extra" DataLoadOptions's added? If so, how would it be possible to apply the DataLoadOptions prior to the the query being compiled?

like image 766
krisg Avatar asked Dec 03 '09 08:12

krisg


People also ask

What is compiled LINQ query?

What a Compiled query in LINQ is. A compiled query is a cached version of the actual query, that we use to get the results. We write the query. For the first time it is parsed or verified for any kind of syntax error in LINQ, then converted into SQL version and is added into cache.

What is a compiled query?

A compiled query is an object that keeps a prepared SQL statement and a delegate to a materializing function. The first one is to be executed at the server to get rows related to the query, the second one transforms a result set into a sequence of entity objects.

How are LINQ queries executed?

LINQ queries are always executed when the query variable is iterated over, not when the query variable is created. This is called deferred execution. You can also force a query to execute immediately, which is useful for caching query results.

What is LINQ query in SQL Server?

LINQ to SQL is a component of . NET Framework version 3.5 that provides a run-time infrastructure for managing relational data as objects. Relational data appears as a collection of two-dimensional tables (relations or flat files), where common columns relate tables to each other.


1 Answers

In the setter property of the DataContext class, there is a condition that checks if the DataContext has any objects in its Cache, and the LoadOptions is NOT null, and the LoadOptions instance you are trying to set is not the same as the one already set, then you get that exception.

Alternative #1. Create a new Context for each query (probably not a good idea)
Alternative #2. Call the ClearCache method using reflection, then make a new LoadOptions statically, assign it to the Context, then finally, get the compiled query.

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;
    }
}
like image 62
Marcel Valdez Orozco Avatar answered Oct 05 '22 10:10

Marcel Valdez Orozco