ORMQueryConstructionException when trying to use generics

Posts   
 
    
HcD avatar
HcD
User
Posts: 214
Joined: 12-May-2005
# Posted on: 13-Feb-2016 20:30:54   

Using LLBLGen 4.2, VS2015, SQL2012

Hello, I have simplified this case to a very simple data model : 2 tables "Company" and "Group", with a n-1 relationship, so a company has a FK to a group. At one time I need to fetch the Companies for a given group, so that's very simple:


    using (var adapter = CreateAdapter())
            {
                var metaData = new LinqMetaData(adapter);
                var query = metaData.Company.Where(x => x.GroupId == groupid);//groupid is a nullable Int64 passed in via parameter
                var result =  await query.ToListAsync();
                return result;
            }

Now, in the future I foresee to have a lot of different entities to have a Group, so I've made an interface :


    public interface IHasGroup
    {
        long GroupId { get; }
    }

and in the custom class of the CompanyEntity just add this interface.


public partial class CompanyEntity : IHasGroup {} //the GroupId is a generated field from LLBLGen

Then I've made a fluent generic extension method :


   public static class QueryFilterExtensions
    {
     public static IQueryable<T> ApplyGroupFilter<T>(this IQueryable<T> query, int? groupId) where T : IHasGroup
        {
            if (groupId.HasValue)
                query = query.Where(x => x.GroupId == groupId.Value);
            return query;
        }
  }

so I could use the code :


        using (var adapter = CreateAdapter())
            {
                var metaData = new LinqMetaData(adapter);
                var query = metaData.Company.ApplyGroupFilter(groupid);
                //var query = metaData.Company.Where(x => x.GroupId == groupid);
                var result =  await query.ToListAsync();
                return result;
            }

But this results in the error :

Message: "An error has occurred.", ExceptionMessage: "The binary expression '(Convert(Entity(CompanyEntity)).GroupId == 1)' can't be converted to a predicate expression.", ExceptionType: "SD.LLBLGen.Pro.ORMSupportClasses.ORMQueryConstructionException", StackTrace: " at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.QueryExpressionBuilder.HandleBinaryExpressionSeparateOperands(BinaryExpression expressionToHandle, Expression leftSide, Expression rightSide) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.QueryExpressionBuilder.HandleBinaryExpressionBooleanOperator(BinaryExpression expressionToHandle) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleExpression(Expression expressionToHandle) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.QueryExpressionBuilder.HandleExpression(Expression expressionToHandle) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.QueryExpressionBuilder.HandleLambdaExpression(LambdaExpression expressionToHandle) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleExpression(Expression expressionToHandle) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.QueryExpressionBuilder.HandleExpression(Expression expressionToHandle) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.QueryExpressionBuilder.HandleWhereExpression(WhereExpression expressionToHandle) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleExpression(Expression expressionToHandle) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.QueryExpressionBuilder.HandleExpression(Expression expressionToHandle) at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProProviderBase.HandleExpressionTree(Expression expression) at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProProviderBase.<PerformExecuteAsync>d__6.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.ConfiguredTaskAwaitable1.ConfiguredTaskAwaiter.GetResult() at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProProviderBase.<ExecuteAsync>d__21.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.ConfiguredTaskAwaitable1.ConfiguredTaskAwaiter.GetResult() at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProQuery1.<ExecuteAsync>d__41.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.ConfiguredTaskAwaitable1.ConfiguredTaskAwaiter.GetResult() at SD.LLBLGen.Pro.LinqSupportClasses.QueryableExtensionMethods.<ToListAsync>d__41.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter1.GetResult() at Bestmix.Backend.Business.Repositories.EntityRepositories.CompanyRepository.<GetEntitiesForOverview>d__0.MoveNext() in D:\FAAS2.0\Src\Bestmix.Poc\Bestmix.Backend.Business\Repositories\EntityRepositories\CompanyRepository.cs:line 25 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter1.GetResult() at Bestmix.Backend.WebApi.Controllers.EntityController1.<GetEntitiesForOverview>d__2.MoveNext() in D:\FAAS2.0\Src\Bestmix.Poc\Bestmix.Backend.WebApi\Controllers\EntityController.cs:line 37 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter1.GetResult() at System.Threading.Tasks.TaskHelpersExtensions.<CastToObject>d__31.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter1.GetResult() at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter1.GetResult() at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()" }

If I change the extension method to a non-templated generic :


        public static IQueryable<CompanyEntity> ApplyGroupFilter(this IQueryable<CompanyEntity> query, int? groupId)
        {
            if (groupId.HasValue)
                query = query.Where(x => x.GroupId == groupId.Value);
            return query;
        }

then it works, but of course I can only use it on CompanyEntity's , and I would like to use it on all entities that implement "IHasGroup"

Is there something I'm missing here ?

Kind regards, Sven.

HcD avatar
HcD
User
Posts: 214
Joined: 12-May-2005
# Posted on: 13-Feb-2016 20:42:09   

Fixed !!!

It seems that all I needed to do was add "CommonEntityBase" as a generic requirement,

so

      public static IQueryable<T> ApplyGroupFilter<T>(this IQueryable<T> query, int? groupId) where T : [b]CommonEntityBase[/b], IHasGroup

instead of

     public static IQueryable<T> ApplyGroupFilter<T>(this IQueryable<T> query, int? groupId) where T : IHasGroup

So this thread can be closed, I hope someone else finds this useful when they encounter the same error when trying to dynamically construct queries ....

Kind regards, Sven.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 14-Feb-2016 11:12:44   

Thanks for sharing, Sven!

Frans Bouma | Lead developer LLBLGen Pro