- Home
- LLBLGen Pro
- Bugs & Issues
PredicateBuilder - Unable to cast object of type 'System.Linq.Expressions.MethodCallExpressionN' to type 'System.Linq.Expressions.LambdaExpression'
Joined: 18-Sep-2008
We are using LLBLGen 4.2.20160517 and PredicateBuilder from attachment. The following query fails with exception if predicate is used but works fine if the predicate expression is used directly.
// fails
var expectedSldsFilter = PredicateBuilder.Null<RelatedItemEntity>().And(r => r.ChildType == expectedSldType && r.ParentType == repairType);
var fulfilledSldsIds = MetaData.ExpectedSld.Where(x => x.FulfilledSldId.HasValue && MetaData.RelatedItem.Any(expectedSldsFilter.And(r => r.ChildId == x.Id))).Select(x => x.FulfilledSldId.Value).Take(10).ToList();
// works fine
var fulfilledSldsIds = MetaData.ExpectedSld.Where(x => x.FulfilledSldId.HasValue && MetaData.RelatedItem.Any(r => r.ChildType == expectedSldType && r.ParentType == repairType && r.ChildId == x.Id)).Select(x => x.FulfilledSldId.Value).Take(10).ToList();
Exception Details:
[InvalidCastException: Unable to cast object of type 'System.Linq.Expressions.MethodCallExpressionN' to type 'System.Linq.Expressions.LambdaExpression'.]
SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleMethodCallAllAny(MethodCallExpression expressionToHandle, Boolean isAll) +390
SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleQueryableExtensionMethod(MethodCallExpression expressionToHandle) +1529
SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleMethodCallPerType(MethodCallExpression expressionToHandle, Type declaringType) +363
SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleMethodCallExpression(MethodCallExpression expressionToHandle) +1936
SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleExpression(Expression expressionToHandle) +4808
SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleExpression(Expression expressionToHandle) +130
SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleBinaryExpression(BinaryExpression expressionToHandle) +190
SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleBinaryExpression(BinaryExpression expressionToHandle) +1020
SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleBinaryExpressionBooleanOperator(BinaryExpression expressionToHandle) +50
SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleExpression(Expression expressionToHandle) +4104
SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleExpression(Expression expressionToHandle) +130
SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleLambdaExpression(LambdaExpression expressionToHandle) +112
SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleExpression(Expression expressionToHandle) +4913
SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleExpression(Expression expressionToHandle) +130
SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleMethodCallWhere(MethodCallExpression expressionToHandle) +443
SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleQueryableExtensionMethod(MethodCallExpression expressionToHandle) +2713
SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleMethodCallPerType(MethodCallExpression expressionToHandle, Type declaringType) +363
SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleMethodCallExpression(MethodCallExpression expressionToHandle) +1936
SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleExpression(Expression expressionToHandle) +4808
SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleExpression(Expression expressionToHandle) +130
SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleMethodCallSelect(MethodCallExpression expressionToHandle) +175
SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleQueryableExtensionMethod(MethodCallExpression expressionToHandle) +2399
SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleMethodCallPerType(MethodCallExpression expressionToHandle, Type declaringType) +363
SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleMethodCallExpression(MethodCallExpression expressionToHandle) +1936
SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleExpression(Expression expressionToHandle) +4808
SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleExpression(Expression expressionToHandle) +130
SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleMethodCallTake(MethodCallExpression expressionToHandle) +175
SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleQueryableExtensionMethod(MethodCallExpression expressionToHandle) +2625
SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleMethodCallPerType(MethodCallExpression expressionToHandle, Type declaringType) +363
SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleMethodCallExpression(MethodCallExpression expressionToHandle) +1936
SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleExpression(Expression expressionToHandle) +4808
SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleExpression(Expression expressionToHandle) +130
SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProProviderBase.HandleExpressionTree(Expression expression) +437
SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProProviderBase.PerformExecute(Expression expression, Type resultType) +56
SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProProviderBase.System.Linq.IQueryProvider.Execute(Expression expression) +86
SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProQuery`1.Execute() +65
SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator() +63
System.Collections.Generic.List`1..ctor(IEnumerable`1 collection) +177
System.Linq.Enumerable.ToList(IEnumerable`1 source) +36
Filename | File size | Added on | Approval |
---|---|---|---|
PredicateBuilder.cs | 1,758 | 22-Jul-2016 15:54.21 | Approved |
Would it work if you try the following?
var fulfilledSldsIds = MetaData.ExpectedSld.Where(x => x.FulfilledSldId.HasValue && MetaData.RelatedItem.Any(expectedSldsFilter)).Select(x => x.FulfilledSldId.Value).Take(10).ToList();
If it does, can you try to add the extra filter to the PredicateBuilder before using it in the query.
Also please enable level 3 tracing on the linq provider (see: http://www.llblgen.com/Documentation/5.0/LLBLGen%20Pro%20RTF/Using%20the%20generated%20code/gencode_troubleshootingdebugging.htm#conventions) which should give you the full expression tree in lambda method calls, so the differences should be clear from that.
Joined: 18-Sep-2008
Otis wrote:
Also please enable level 3 tracing on the linq provider (see: http://www.llblgen.com/Documentation/5.0/LLBLGen%20Pro%20RTF/Using%20the%20generated%20code/gencode_troubleshootingdebugging.htm#conventions) which should give you the full expression tree in lambda method calls, so the differences should be clear from that.
There is only one entry for the query and it immidiately fails:
: Initial expression to process:
value(SD.LLBLGen.Pro.LinqSupportClasses.DataSource2`1[Stream.CustomerDb.DataLayer.EntityClasses.ExpectedSldEntity]).Where(x => (x.FulfilledSldId.HasValue AndAlso value(Stream.DataLayer.Repositories.RecordRepository).MetaData.RelatedItem.Any(value(Stream.DataLayer.Repositories.RecordRepository+<>c__DisplayClass10_0).expectedSldsFilter.And(r => (r.ChildId == x.Id))))).Select(x => x.FulfilledSldId.Value).Take(10)
Joined: 18-Sep-2008
Walaa wrote:
Would it work if you try the following?
var fulfilledSldsIds = MetaData.ExpectedSld.Where(x => x.FulfilledSldId.HasValue && MetaData.RelatedItem.Any(expectedSldsFilter)).Select(x => x.FulfilledSldId.Value).Take(10).ToList();
If it does, can you try to add the extra filter to the PredicateBuilder before using it in the query.
No, it won't work from business logic perspective because we need to apply correlated filter for RelatedItem by ChildId and there is no way to add that filter to predicate, at least I don't know of a way. But from perspective whether it works or not - it doesn't and it throws "Unable to cast object of type 'SD.LLBLGen.Pro.LinqSupportClasses.ExpressionClasses.InMemoryEvalCandidateExpression' to type 'System.Linq.Expressions.LambdaExpression'."
zihotki wrote:
Otis wrote:
Also please enable level 3 tracing on the linq provider (see: http://www.llblgen.com/Documentation/5.0/LLBLGen%20Pro%20RTF/Using%20the%20generated%20code/gencode_troubleshootingdebugging.htm#conventions) which should give you the full expression tree in lambda method calls, so the differences should be clear from that.
There is only one entry for the query and it immidiately fails:
: Initial expression to process: value(SD.LLBLGen.Pro.LinqSupportClasses.DataSource2`1[Stream.CustomerDb.DataLayer.EntityClasses.ExpectedSldEntity]).Where(x => (x.FulfilledSldId.HasValue AndAlso value(Stream.DataLayer.Repositories.RecordRepository).MetaData.RelatedItem.Any(value(Stream.DataLayer.Repositories.RecordRepository+<>c__DisplayClass10_0).expectedSldsFilter.And(r => (r.ChildId == x.Id))))).Select(x => x.FulfilledSldId.Value).Take(10)
Ok, but could you also use the tracing with the code which works. What I'm after is to get the proper lambda.
Also, keep in mind that the tree is too complex for us to build a repro for to debug it. Please cut down the expression to the bar minimum which fails.
Joined: 18-Sep-2008
Otis wrote:
zihotki wrote:
Otis wrote:
Also please enable level 3 tracing on the linq provider (see: http://www.llblgen.com/Documentation/5.0/LLBLGen%20Pro%20RTF/Using%20the%20generated%20code/gencode_troubleshootingdebugging.htm#conventions) which should give you the full expression tree in lambda method calls, so the differences should be clear from that.
There is only one entry for the query and it immidiately fails:
: Initial expression to process: value(SD.LLBLGen.Pro.LinqSupportClasses.DataSource2`1[Stream.CustomerDb.DataLayer.EntityClasses.ExpectedSldEntity]).Where(x => (x.FulfilledSldId.HasValue AndAlso value(Stream.DataLayer.Repositories.RecordRepository).MetaData.RelatedItem.Any(value(Stream.DataLayer.Repositories.RecordRepository+<>c__DisplayClass10_0).expectedSldsFilter.And(r => (r.ChildId == x.Id))))).Select(x => x.FulfilledSldId.Value).Take(10)
Ok, but could you also use the tracing with the code which works. What I'm after is to get the proper lambda.
Also, keep in mind that the tree is too complex for us to build a repro for to debug it. Please cut down the expression to the bar minimum which fails.
Sorry, my bad, here it is:
: Initial expression to process:
value(SD.LLBLGen.Pro.LinqSupportClasses.DataSource2`1[Stream.CustomerDb.DataLayer.EntityClasses.ExpectedSldEntity]).Where(x => (x.FulfilledSldId.HasValue AndAlso value(Stream.DataLayer.Repositories.RecordRepository).MetaData.RelatedItem.Any(r => (((r.ChildType == value(Stream.DataLayer.Repositories.RecordRepository+<>c__DisplayClass10_0).expectedSldType) AndAlso (r.ParentType == value(Stream.DataLayer.Repositories.RecordRepository+<>c__DisplayClass10_0).repairType)) AndAlso (r.ChildId == x.Id))))).Select(x => x.FulfilledSldId.Value).Take(10)
Method Enter: CreatePagingSelectDQ
Method Enter: CreateSelectDQ
Method Enter: CreateSelectDQ
Method Enter: CreateSubQuery
Method Enter: CreateSelectDQ
Method Enter: CreateSelectDQ
Method Exit: CreateSelectDQ
Method Exit: CreateSubQuery
Method Exit: CreateSelectDQ
Method Exit: CreatePagingSelectDQ: no paging.
Method Enter: DataAccessAdapterBase.OpenConnection
Method Exit: DataAccessAdapterBase.OpenConnection
Ok, and that's the minimal expression that fails, removing any part of it makes it work? As we can't build a repro with such a complex tree.
You have given no information regarding what is used in the query, so we can't repro this.
The queries aren't the same btw:
// fails
var expectedSldsFilter = PredicateBuilder.Null<RelatedItemEntity>().And(r => r.ChildType == expectedSldType && r.ParentType == repairType);
var fulfilledSldsIds = MetaData.ExpectedSld.Where(x => x.FulfilledSldId.HasValue && MetaData.RelatedItem.Any(expectedSldsFilter.And(r => r.ChildId == x.Id))).Select(x => x.FulfilledSldId.Value).Take(10).ToList();
// works fine
var fulfilledSldsIds = MetaData.ExpectedSld.Where(x => x.FulfilledSldId.HasValue && MetaData.RelatedItem.Any(r => r.ChildType == expectedSldType && r.ParentType == repairType && r.ChildId == x.Id)).Select(x => x.FulfilledSldId.Value).Take(10).ToList();
The 'works fine' one appends r.ChildId==x.Id to the same predicate, but the predicate builder one doesn't, it's a separate lambda. You use a parameter with the same name but internally it's a different one.
I suspect (but just a guess, these linq expression trees are huge to debug, hence my request for a minimum query which fails) that this will work too:
var expectedSldsFilter = PredicateBuilder.Null<RelatedItemEntity>().And(r => r.ChildType == expectedSldType && r.ParentType == repairType && r.ChildId == x.Id);
var fulfilledSldsIds = MetaData.ExpectedSld.Where(x => x.FulfilledSldId.HasValue && MetaData.RelatedItem.Any(expectedSldsFilter)).Select(x => x.FulfilledSldId.Value).Take(10).ToList();
Is 'MetaData' a static property btw? If so and you're using adapter, don't do that, the live adapter isn't sharable.
I think the .And() call in the expression which fails is the problem. The thing is: that's an extension method of the predicate builder which will replace the expression with a different one.
However you embed that .And() call in the Any() call. This means that the call to 'And()' isn't done there, but is embedded as a MethodCallExpression, and is evaluated when the whole tree is evaluated, and then it's unexpected (and can't be handled, as the And() call is unknown to the provider).
To fix it do:
var expectedSldsFilter = PredicateBuilder.Null<RelatedItemEntity>().And(r => r.ChildType == expectedSldType && r.ParentType == repairType);
var filterToUse = expectedSldsFilter.And(r => r.ChildId == x.Id);
var fulfilledSldsIds = MetaData.ExpectedSld.Where(x => x.FulfilledSldId.HasValue && MetaData.RelatedItem.Any(filterToUse)).Select(x => x.FulfilledSldId.Value).Take(10).ToList();
As in this case, the And() call is evaluated directly and replaces the expression with an AndAlso expression, which will then be embedded in the Any() call.
Again, if it fails, please trim things down to the bare minimum before we can do anything with it.
Joined: 18-Sep-2008
Otis wrote:
Ok, and that's the minimal expression that fails, removing any part of it makes it work? As we can't build a repro with such a complex tree.
You have given no information regarding what is used in the query, so we can't repro this.
The queries aren't the same btw:
// fails var expectedSldsFilter = PredicateBuilder.Null<RelatedItemEntity>().And(r => r.ChildType == expectedSldType && r.ParentType == repairType); var fulfilledSldsIds = MetaData.ExpectedSld.Where(x => x.FulfilledSldId.HasValue && MetaData.RelatedItem.Any(expectedSldsFilter.And(r => r.ChildId == x.Id))).Select(x => x.FulfilledSldId.Value).Take(10).ToList(); // works fine var fulfilledSldsIds = MetaData.ExpectedSld.Where(x => x.FulfilledSldId.HasValue && MetaData.RelatedItem.Any(r => r.ChildType == expectedSldType && r.ParentType == repairType && r.ChildId == x.Id)).Select(x => x.FulfilledSldId.Value).Take(10).ToList();
The 'works fine' one appends r.ChildId==x.Id to the same predicate, but the predicate builder one doesn't, it's a separate lambda. You use a parameter with the same name but internally it's a different one.
No, they are the same from the perspective of expressions logic (boolean logic) - r=a&b&c is the same as d=a&b; r=d&c, or r=a=(a&b)&c, or r=a&(b&c), it shouldn't matter at all. But if linq provider doesn't support that - that's a different thing.
Otis wrote:
I suspect (but just a guess, these linq expression trees are huge to debug, hence my request for a minimum query which fails) that this will work too:
var expectedSldsFilter = PredicateBuilder.Null<RelatedItemEntity>().And(r => r.ChildType == expectedSldType && r.ParentType == repairType && r.ChildId == x.Id); var fulfilledSldsIds = MetaData.ExpectedSld.Where(x => x.FulfilledSldId.HasValue && MetaData.RelatedItem.Any(expectedSldsFilter)).Select(x => x.FulfilledSldId.Value).Take(10).ToList();
Is 'MetaData' a static property btw? If so and you're using adapter, don't do that, the live adapter isn't sharable.
The code you suggested won't compile because x.Id is not defined there, it's coming from the lambda in Where clause and there is no easy way, as far as know, to create a predicate for such case.
Here is the smallest failing query, it fails only if I add correlation condition (r.ChildId == x.Id), without it it works fine:
var expectedSldsFilter = PredicateBuilder.Null<RelatedItemEntity>();
MetaData.ExpectedSld.Where(x => MetaData.RelatedItem.Any(expectedSldsFilter.And(r => r.ChildId == x.Id))).Take(10).ToList()
Metadata is an instance property inialized for a Repository. The simplified models are:
public class ExpectedSldEntity{
public int Id {get; set;}
}
public class RelatedItemEntity{
public int ParentId {get; set;}
public int ParentType {get;set;}
public int ChildId {get; set;}
puclic int ChildType {get; set;}
}
zihotki wrote:
Otis wrote:
Ok, and that's the minimal expression that fails, removing any part of it makes it work? As we can't build a repro with such a complex tree.
You have given no information regarding what is used in the query, so we can't repro this.
The queries aren't the same btw:
// fails var expectedSldsFilter = PredicateBuilder.Null<RelatedItemEntity>().And(r => r.ChildType == expectedSldType && r.ParentType == repairType); var fulfilledSldsIds = MetaData.ExpectedSld.Where(x => x.FulfilledSldId.HasValue && MetaData.RelatedItem.Any(expectedSldsFilter.And(r => r.ChildId == x.Id))).Select(x => x.FulfilledSldId.Value).Take(10).ToList(); // works fine var fulfilledSldsIds = MetaData.ExpectedSld.Where(x => x.FulfilledSldId.HasValue && MetaData.RelatedItem.Any(r => r.ChildType == expectedSldType && r.ParentType == repairType && r.ChildId == x.Id)).Select(x => x.FulfilledSldId.Value).Take(10).ToList();
The 'works fine' one appends r.ChildId==x.Id to the same predicate, but the predicate builder one doesn't, it's a separate lambda. You use a parameter with the same name but internally it's a different one.
No, they are the same from the perspective of expressions logic (boolean logic) - r=a&b&c is the same as d=a&b; r=d&c, or r=a=(a&b)&c, or r=a&(b&c), it shouldn't matter at all. But if linq provider doesn't support that - that's a different thing.
Semantically they're the same, but in the expression tree they're not.
Anyway, it's beside the point, as the problem is elsewhere ->
The problem is, as I described earlier, the '.And()' call inside the main query, it has to be done outside the main query, otherwise it will get embedded in the expression tree instead of being called, so the 'And()' call will then be embedded as a MethodCallExpression which is then running into a problem because the And() call is unknown (as the predicate builder is an external class).
So first build the full predicate, store it in a variable, then pass that variable as the predicate to a method like where/any etc.
The reason is that .And() is then actually executed in-place, otherwise it's not, as the compiler will simply create a methodcall expression.
At least that's my assumption, as I haven't run the expression in practice yet, but looking at the expression tree as passed to the provider, it looks that way.
I could reproduce it with:
[Test]
public void InlinedPredicateBuilderUsageTest()
{
var filter = PredicateBuilder.Null<OrderEntity>();
using(var adapter = new DataAccessAdapter())
{
var metaData = new LinqMetaData(adapter);
var q = metaData.Customer.Where(x=>metaData.Order.Any(filter.And(r=>r.CustomerId == x.CustomerId))).Take(10).ToList();
foreach(var v in q)
{
}
}
}
Which, as expected, is caused by the 'And' call, as described.
The main problem is that predicate builder works on (p)=>p.Field <operator> <operand>, kind of predicates: it works on the parameter 'p' passed in. Your particular lambda works on two parameters, not one, namely also the one passed into the enclosing lambda.
So to solve this I did:
[Test]
public void InlinedPredicateBuilderUsageTest()
{
using(var adapter = new DataAccessAdapter())
{
var metaData = new LinqMetaData(adapter);
var filter = PredicateBuilder.Null<CustomerEntity>();
filter = filter.And(c=>metaData.Order.Any(o=>o.CustomerId == c.CustomerId));
var q = metaData.Customer.Where(filter).Take(10).ToList();
foreach(var v in q)
{
}
}
}
In any case, it 'works', but you have to understand: dynamic where clauses in linq is tricky, due to the fact linq is rigid. For more flexible where clauses without problems you could look at QuerySpec.
Joined: 18-Sep-2008
I see, that's a valid concern. But that won't work in our case because we need to change the expression in Any subquery depending on the settings:
var orderPredicate = PredicateBuilder.Null<OrderEntity>();
if (filter.NewerThan.HasValue){
orderPredicate = orderPredicate.And(x => x.Date >= filter.NewerThan.Value);
}
// ... etc.
We need to implement very complex filtering and PredicateBuilder was the only good solution for this otherwise we'll need to have a lot of repetitive queries, at least one for each logical branch. For EntityFramework we could have used LinqKit which supports such kind of queries but it doesn't work for LLBLGen, unfortunately. We'll need to think of other options.
zihotki wrote:
I see, that's a valid concern. But that won't work in our case because we need to change the expression in Any subquery depending on the settings:
var orderPredicate = PredicateBuilder.Null<OrderEntity>(); if (filter.NewerThan.HasValue){ orderPredicate = orderPredicate.And(x => x.Date >= filter.NewerThan.Value); } // ... etc.
Not sure I see why though: the predicate you pass to 'Any()' is now build up front, that's all.
We need to implement very complex filtering and PredicateBuilder was the only good solution for this otherwise we'll need to have a lot of repetitive queries, at least one for each logical branch.
QuerySpec's filtering is more flexible than this, you can create predicates using whatever logic you like, you just append objects:
var predicate = new PredicateExpression();
if(filter.NewerThan.HasValue)
{
predicate.Add(OrderFields.Date.GreaterEqual(filter.Newer.Value));
}
etc.
Then, use it in a query:
var q = qf.Order.WhereExists(filter); // Any is a WHERE EXISTS query
var results = adapter.FetchQuery(q);
You don't have to switch every query to queryspec, the runtime doesn't care: you can switch whenever you need to. I.e. use linq + predicatebuilder when things work fine, and queryspec when you need to do things predicatebuilder doesn't work.
For EntityFramework we could have used LinqKit which supports such kind of queries but it doesn't work for LLBLGen, unfortunately. We'll need to think of other options.
It looks like it does generic expression tree rewriting, not sure why it shouldn't work, but it might be it uses rewriting using EF specific code, I haven't used it.