Multi-part identifier exception using joined query - AdventureWorks example

Posts   
 
    
swilhelm
User
Posts: 1
Joined: 22-Apr-2010
# Posted on: 23-Apr-2010 08:49:58   

Hi there,

I have to build sometimes complex queries and get really often an 'Multi-part identifier' exception. I have now isolated the problem and reproduced it in AdventureWorks database.

I'll think LLBLGen has a problem, when the query has a join from table A to table B but you do not select any data from table B. So the result will be IQueryable<table A>. Trying now to do a second query on the result of the first IQueryable<table A> will throw the 'Multi-part identifier' exception. It seems that LLBLGen will not give table B from the first query an alias because of there are no data selected from this table. I have found a workaround for this issue, see the example attached - but I hope my reproduced error will be fixed, so the workarround is unnecessary. Thank you.

Regards, Stefan

Walaa avatar
Walaa
Support Team
Posts: 14994
Joined: 21-Aug-2005
# Posted on: 23-Apr-2010 11:40:09   

Which LLBLGen runtime library version/build are you using?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39871
Joined: 17-Aug-2003
# Posted on: 23-Apr-2010 12:18:10   

Walaa wrote:

Which LLBLGen runtime library version/build are you using?

according to the repro, the latest build.

We'll look into it

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39871
Joined: 17-Aug-2003
# Posted on: 23-Apr-2010 12:31:24   

I see what's the problem: you join the same element twice using the exact same lambda. (ProductSubCategory).

The problem is that our linq provider currently has a known issue where it assigns aliases to anonymous type members to be able to refer to the real source later on, but in the query there can be multiple times the same anonymous type used while meaning the same thing. Adding the 'let' statement makes the lambda different (the anonymous type is different) so this problem isn't occuring.

Same problem occurs with this query:


LinqMetaData metaData = new LinqMetaData(adapter);
var q = from o in metaData.Order
        join cust in metaData.Customer on o.CustomerId equals cust.CustomerId
        where o.OrderId == 10261
        select new
        {
            CountOfDiscontinuedProducts = Convert.ToInt32(o.OrderDetails.Count(od => od.Product.Discontinued == true)),
            CountOfNotDiscontinuedProducts = Convert.ToInt32(o.OrderDetails.Count(od => od.Product.Discontinued == false)),
        };

It's a tough problem though, as linq is sequenced based and wraps original references into anonymous types, like in a join, so a member of an anonymous type is one side of a join, however in the end query, the side of the join is reachable directly, not through a set of properties on a derived table (nested select). This leads to alias - source links which cause problems if a member of a given anonymous type T is re-used by the compiler. When we wrote the linq provider back in 2008 we didn't anticipate on this, and we found this out more than a year later... It does require a big change inside the linq provider though hence the reason we didn't fix it today. The problem also doesn't occur that often, however that's not something you can use of course.

For v3 we have planned to fix this (which will happen in the next couple of weeks), and if possible, we'll backport the fix to v2.6's linq provider. The problem is that it is rather hard to do, as a 'member' isn't enough apparently to obtain the alias of the real source what it represents, but that means that context info is required, however at multiple places inside a linq expression tree, there's no other context information available. We do have a scope visitor inside the linq provider which might help in this, but it's not said if we can fix it inside our linq provider.

I know the workaround is lame, but it's all we can offer you at this point. Sorry for this lame inconvenience. flushed

Frans Bouma | Lead developer LLBLGen Pro