使用LINQkit在LINQ to Entities Select中调用Expression

bil*_*lly 3 c# linq-to-entities linq-expressions linqkit

这就是我想要做的事情:

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
            }
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

更新:

myExpression 必须与我的查询保持分离,因为我想在多个LINQ查询中重用它.

更新2:

分离myExpressionmyExpression1myExpression2明确指出,我想单独重用他们的事实.

更新3:

添加了LINQkit示例.

问题1抛出:无法将"System.Linq.Expressions.FieldExpression"类型的对象强制转换为"System.Linq.Expressions.LambdaExpression".

问题2抛出:内部.NET Framework数据提供程序错误1025.

Luc*_*tti 6

关于使用LinqKit时的第一个问题,您需要在.Invoke()之前将表达式分配给局部变量.在这个问题上可以找到更完整的解释.

第二个问题是select方法接受一个类型的对象:

Expression<Func<TSource, TResult>>
Run Code Online (Sandbox Code Playgroud)

这意味着您必须提供一个lambda表达式,接受一个TSource对象作为参数并返回一个TResult对象.

您的TSource对象是Item,即您进行查询的表.你的TResult在你的例子中是一个int,就是你在表达式上定义的.

因此,您必须在第二个表达式上调用.Invoke(),将Item对象作为参数传递,方法与传递MyClassDbSet对象"o"的方式相同.实际上,两个select语句只有语法差异,它们本质上也是一样的.

你不应该在表达式上调用.Compile(),这会产生一个:

Func<TSource, TResult>
Run Code Online (Sandbox Code Playgroud)

哪个是表达式树的编译版本的委托,不能转换为SQL表达式.更多信息可以在这里找到 .

它应该与以下更改一起使用:

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)) 
            }
        );
    }
}
Run Code Online (Sandbox Code Playgroud)