The multi-part identifier "LPA_L2.TradeId" could not be bound

Posts   
 
    
Evan
User
Posts: 67
Joined: 02-May-2012
# Posted on: 16-Mar-2018 19:14:57   

Runtime Version 5.3.2, Designer Version 5.2.5.

I'm having an issue where there's a SQL Exception when I use the fluent syntax rather than the join/linq syntax. Both compile and seem logically equivalent. TradeDetail.TradeId is a foreign key to Trade.TradeId, so t.TradeDetails should be equivalent to the join.

This one throws the error: (The multi-part identifier "LPA_L2.TradeId" could not be bound) tempQueryable = tradeQueryable.GravitateSecurityContextFilter(gravitateSecurityContext).SelectMany(t => t.TradeDetails.Select(td => td.Product));

This one works fine:

tempQueryable = from t in tradeQueryable.GravitateSecurityContextFilter(gravitateSecurityContext) join td in tradeDetailQueryable on t.TradeId equals td.TradeId select td.Product;

Also, my initial attempt at it was this: (queryable below is an IQueryable<ProductEntity>, this one compiles too, but throws an error at runtime. see below)

tempQueryable = queryable.Where(p => tradeQueryable.GravitateSecurityContextFilter(gravitateSecurityContext).Any(t => t.TradeDetails.Any(td => td.ProductId == p.ProductId)));

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.ArgumentException: Expression of type 'Gravitate.Domain.Adapter.EntityClasses.TradeEntity' cannot be used for parameter of type 'System.Linq.IQueryable1[Gravitate.Domain.Adapter.EntityClasses.TradeEntity]' of method 'System.Linq.IQueryable1[Gravitate.Domain.Adapter.EntityClasses.TradeEntity] GravitateSecurityContextFilter(System.Linq.IQueryable1[Gravitate.Domain.Adapter.EntityClasses.TradeEntity], Gravitate.Domain.Adapter.DAL.Security.GravitateSecurityContext)' at System.Linq.Expressions.Expression.ValidateOneArgument(MethodBase method, ExpressionType nodeKind, Expression arg, ParameterInfo pi) at System.Linq.Expressions.Expression.ValidateArgumentTypes(MethodBase method, ExpressionType nodeKind, ReadOnlyCollection1& arguments) at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, IEnumerable1 arguments) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleMethodCallPerType(MethodCallExpression expressionToHandle, Type declaringType) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleMethodCallExpression(MethodCallExpression expressionToHandle) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleExpression(Expression expressionToHandle) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleMethodCallAllAny(MethodCallExpression expressionToHandle, Boolean isAll) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleQueryableExtensionMethod(MethodCallExpression expressionToHandle) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleMethodCallPerType(MethodCallExpression expressionToHandle, Type declaringType) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleMethodCallExpression(MethodCallExpression expressionToHandle) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleExpression(Expression expressionToHandle) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleLambdaExpression(LambdaExpression expressionToHandle) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleExpression(Expression expressionToHandle) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleMethodCallWhere(MethodCallExpression expressionToHandle) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleQueryableExtensionMethod(MethodCallExpression expressionToHandle) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleMethodCallPerType(MethodCallExpression expressionToHandle, Type declaringType) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleMethodCallExpression(MethodCallExpression expressionToHandle) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleExpression(Expression expressionToHandle) at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProProviderBase.HandleExpressionTree(Expression expression) at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProProviderBase.System.Linq.IQueryProvider.Execute(Expression expression) at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProQuery1.System.Collections.Generic.IEnumerable<T>.GetEnumerator()

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 19-Mar-2018 05:19:15   

Evan wrote:

Runtime Version 5.3.2, Designer Version 5.2.5.

That seems very unlikely. If you use Designer v5.2.x, the shipped runtime library version are v5.2.x. Could you please double check this versions? (ref...).

Evan wrote:

tempQueryable = tradeQueryable.GravitateSecurityContextFilter(gravitateSecurityContext).SelectMany(t => t.TradeDetails.Select(td => td.Product));

Could you please describe what is GravitateSecurityContextFilter?

Also please post the Generated SQL for that code.

David Elizondo | LLBLGen Support Team
Evan
User
Posts: 67
Joined: 02-May-2012
# Posted on: 22-Mar-2018 15:29:54   

What's very unlikely? You think I fabricated the error?

I am using a version pulled from nuget, but I suppose I could upgrade the designer. Seems unrelated though. In my experience minor updates to designer haven't had hugely impacted the generated code.

Because the code is related to the security of the site, I'm not wanting to post the full code or queries. But, for argument sake, the code in there is adding a .Where that compares fields on the entity to fields on the gravitateSecurityContext object. Similar to this:

return queryable.Where(q => q.MyIntField == securityContext.SomeIntProperty);

Are you wanting me to trace the query that fails?

I've been using LLBLGenPro for a long time, and have seen this error in various combinations of .GroupBy, .SelectMany, .Any, when you get complicated with relationships. There's something causing it to lose track of what's what in the lambda expressions when it turns it into joins/aliases. It is interesting to me that the linq syntax appears to effectively get around this issue. I'm not sure if that's just because it much more closely matches the sql and there's less to infer or what.

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 22-Mar-2018 16:59:41   

What's very unlikely? You think I fabricated the error?

No one said you fabricated anything, I believe Daelmo was afraid you have mistakenly reported the v. numbers.

Anyway, please avoid any versioning mismatch. Upgrade the designer, re-generate the code, and report back.

We trust your debugging, but we need to repro your case on exactly the same environment.

Thanks,

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 22-Mar-2018 18:47:20   

Evan wrote:

What's very unlikely? You think I fabricated the error?

I am using a version pulled from nuget, but I suppose I could upgrade the designer. Seems unrelated though. In my experience minor updates to designer haven't had hugely impacted the generated code.

Please use the versions of the runtime that's the same as the version of the designer and the generated code. What you're doing isn't supported, as we need to be able to change things across versions (and we do that actually). It might 'work' but it's not guaranteed.

That said, your issue isn't caused by that but likely by the fact the from x in ... syntaxis results in a different SelectMany() call (another overload) than the one you're using in the direct call to SelectMany(). SelectMany is a nasty method to support in a linq provider, so we went for the one that's generated by the compilers. I have to check, but I think that's the cause. (The overload with projectors is key). It loses track indeed with sources where they come from if things aren't matching what the compilers generate, as it's sometimes impossible to do. (Consider using a custom class for the projection in a Join() call: what property matches which ctor argument so it's possible to track its source back (so the right alias can be assigned)? that's usually the root of things going off the cliff in linq providers disappointed I wish I could solve that but it's caused by the design of how linq expression trees work and the linq API)

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 23-Mar-2018 10:58:45   

Your 'join' using query isn't technically equivalent to the selectmany call btw: a SelectMany() is in general a cross join, however if it detects a navigation it will try to convert it into an outer join as that's in general the intend. So in this case it results in the same sql, but doesn't have to in general. If you want to do an outer join and not a cross join, don't use SelectMany.

Your initial query works by moving a ')' to a different spot:

tempQueryable = tradeQueryable.GravitateSecurityContextFilter(gravitateSecurityContext).SelectMany(t => t.TradeDetails).Select(td => td.Product);

This works, because it can reason about the element that select many works on and moves the projection outside the selectmany.

A typical query with selectmany using 'normal' linq syntax is using 2 from clauses, so in your case that would be:

tempQueryable = from t in tradeQueryable.GravitateSecurityContextFilter(gravitateSecurityContext)
                from td in tradeDetailQueryable
                where t.TradeId equals td.TradeId
                select td.Product;

or

tempQueryable = from t in tradeQueryable.GravitateSecurityContextFilter(gravitateSecurityContext)
                from td in t.TradeDetails
                select td.Product;

Using these you'll see if you enable tracing, it will use a different SelectMany() overload, namely the one with a projection. This is required as it tells the provider what projection is used to create the joined set from the sequence.

Another one, which is equal to what the 'normal' linq sequence creates, is this one:


tempQueryable = tradeQueryable.GravitateSecurityContextFilter(gravitateSecurityContext).SelectMany(t => t.TradeDetails, (t, td)=>td.Product);

This also creates the most efficient query as it knows how to navigate and it realizes it can use a relationship.

Join, SelectMany, they need to have a projection lambda as second argument. The overload you're using leads to less stellar results wink Hope this helps

Frans Bouma | Lead developer LLBLGen Pro
Evan
User
Posts: 67
Joined: 02-May-2012
# Posted on: 13-Apr-2018 18:04:09   

Thanks Frans, That was very helpful. I'm installing the matching version of the designer.

It does look like there was a refactoring change. The entities have SetupSync and SetupDesync that were change from calling PerformDesetupSyncRelatedEntity to calling DesetupSync. Is that a big concern or was that backward compatible? It didn't have compile errors on the new libraries...

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 16-Apr-2018 14:16:35   

Evan wrote:

Thanks Frans, That was very helpful. I'm installing the matching version of the designer.

It does look like there was a refactoring change. The entities have SetupSync and SetupDesync that were change from calling PerformDesetupSyncRelatedEntity to calling DesetupSync. Is that a big concern or was that backward compatible? It didn't have compile errors on the new libraries...

What exactly do you mean with 'that were changed from': did you change that yourself? Generating code using v5.3 works with the 5.3 runtime, so if you generate code with v5.2 it needs v5.2, and generating code with v5.4 will require v5.4. The latter is especially true as we refactored the generated code in v5.4 quite a bit.

Frans Bouma | Lead developer LLBLGen Pro
Evan
User
Posts: 67
Joined: 02-May-2012
# Posted on: 17-Apr-2018 19:45:31   

Sorry, didn't word that correctly. Just saying there was a refactoring change within those methods. When generating code from the older version it was calling, "PerformDesetupSyncRelatedEntity", in the newer version it is calling "DesetupSync". That being said I was curious if the old one was left there for backwards compatibility since it compiles...

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 17-Apr-2018 21:33:28   

aaahhh now I see simple_smile The newer code was refactored to be more compact if I recall correctly (have to lookup the change in svn), the original method is called by the (de)setupSync method.

In v5.4 this is all moved to the base class so this is no more in the generated code, in v5.3 it's still there indeed.

Frans Bouma | Lead developer LLBLGen Pro