Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Call Expression within a LINQ to Entities Select with LINQkit

Here's what I want to do :

class MyDbContext : DbContext 
{
    private static Expression<Func<MyClass, int>> myExpression1 = x => /* something complicated ... */;
    private static Expression<Func<Item, int>> myExpression2 = x => /* something else complicated ... */;

    public object GetAllData()
    {
        return (
            from o in MyClassDbSet.AsExpandable() 
            select new 
            {
                data1 = myExpression1.Invoke(o),                      // problem 1
                data2 = o.Items.Select(myExpression2.Compile())       // problem 2
            }
        );
    }
}

UPDATE :

myExpression has to stay separated from my query, because I want to reuse it in multiple LINQ queries.

UPDATE 2 :

Separated myExpression into myExpression1 and myExpression2 to make clear the fact that I want to reuse them separately.

UPDATE 3 :

Added LINQkit to example.

Problem 1 throws : Unable to cast an object of type 'System.Linq.Expressions.FieldExpression' to type 'System.Linq.Expressions.LambdaExpression'.

Problem 2 throws : Internal .NET Framework Data Provider error 1025.

like image 768
billy Avatar asked Mar 23 '23 03:03

billy


1 Answers

On the first problem when using LinqKit you need to assign your expression to a local variable before .Invoke()ing it. More complete explanation can be found on this question.

The second problem is that the select method accept a object of type:

Expression<Func<TSource, TResult>>

Which means that you must supply a lambda expression accepting a TSource object as a parameter and returning a TResult object.

Your TSource object is Item, that is the table you are making your query from. Your TResult is a int in your example, that is what you defined on the expression.

So you must call .Invoke() on the second expression passing a Item object as a parameter, in the same way that you passed the MyClassDbSet object "o". Actually, there is only syntactical diference on both select statements, they essentialy do the same thing.

And you should not call .Compile() on the expressions, this produces a:

Func<TSource, TResult>

Which is a delegate to the compiled version of the expression tree and cannot be translated into a SQL expression. More information can be found here.

It should work with the following changes:

class MyDbContext : DbContext 
{
    private static Expression<Func<MyClass, int>> myExpression1 = x => /* something complicated ... */;
    private static Expression<Func<Item, int>> myExpression2 = x => /* something else complicated ... */;

    public object GetAllData()
    {
        Expression<Func<MyClass, int>> myLocalExpression1 = myExpression1;
        Expression<Func<MyClass, int>> myLocalExpression2 = myExpression2;

        return (
            from o in MyClassDbSet.AsExpandable() 
            select new 
            {
                data1 = myLocalExpression1.Invoke(o),
                data2 = o.Items.Select(item => myLocalExpression1.Invoke(item)) 
            }
        );
    }
}
like image 175
Lucas Corsaletti Avatar answered Apr 06 '23 10:04

Lucas Corsaletti