Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using a delegate CompiledQuery in a join?

Tags:

c#

linq-to-sql

I have a question related to this previous question of mine. In an existing bit of LINQ which involves a number of joins, I'm trying to take each separate method comprising the join and convert it to a CompiledQuery.

First, the normal LINQ method:

private IQueryable<Widget> GetWidgetQuery()
{
    return db.Widgets.Where(u => (!u.SomeField.HasValue || !u.SomeField.Value));
}

And here, a delegate (field) definition for a CompiledQuery along these lines:

private static readonly Func<DBDataContext, IQueryable<Widget>> GetWidgetQuery = 
    CompiledQuery.Compile((DBDataContext db) => 
    db.Widgets.Where(u => (!u.SomeField.HasValue || !u.SomeField.Value)));

If I hover over the normal LINQ statement for the method GetWidgetQuery(), I see that it's a method as below:

(method) IQueryable<Widget> GetWidgetQuery()

However, the compiled query delegate (field) differs as follows:

(field) Func<DBDataContext, IQueryable<Widget>> GetWidgetQuery

Upon executing the latter as part of the LINQ statement, the syntax differs as follows. First, the normal LINQ's participation in the join:

var myquery =
    from wxr in GetWidgetXRQuery()
    join w in GetWidgetQuery() on wxr.WidgetID equals w.ID
    select new DTO.WidgetList
    {
        ...
    }

And here, the invocation of the CompiledQuery in the form of the delegate:

var myquery =
    from wxr in GetWidgetXRQuery()
    join w in GetWidgetQuery.Invoke(myContext) on wxr.WidgetID equals w.ID
    select new DTO.WidgetList
    {
        ...
    }

The former returns the expected result set; the latter, when I attempt myquery.ToList(), yields a stackoverflow exception, in part related to this limitation of .NET 3.5, I think.

Can someone please help me understand how the compiled statement existing as a field (or I guess I should say a delegate) rather than a method is killing my query? In short I know what I'm doing is wrong, but I'm not sure I understand what I misunderstand.

like image 342
Darth Continent Avatar asked Nov 14 '22 18:11

Darth Continent


1 Answers

I tried doing roughly the same thing you're doing on EF 4, and everything seems to work fine. So it's either an EF 3.5 issue, or it has something to do with your implementation of GetWidgetXRQuery, or some combination of the two.

But the real point I'd like to make is that, as Roy Goode stated in an answer to your previous question, you lose all the advantages of a precompiled query once you extend that query in any way. By trying to perform a Join on your query, you are converting it to just a plain old query. So you might as well just use the non-compiled version which appears to work for you.

Update

Realized you were talking about LINQ to SQL. This sort of query does appear to have support in Entity Framework, but not LINQ to SQL. In .NET 4, I'm getting the following error:

An IQueryable that returns a self-referencing Constant expression is not supported.

That doesn't mean much to me, but I'm guessing that it has something to do with the way the compiled query is represented internally. I still get the same error if I evaluate the query into a variable and use that variable in the query later, so it clearly has nothing to do with the difference between a delegate and a function. I still maintain that a compiled query is not appropriate to use here. Either you need to create one big compiled query to represent the whole query you want to perform, or you need to use regular queries if you want to piece them together this way.

like image 101
StriplingWarrior Avatar answered Dec 24 '22 01:12

StriplingWarrior