使用LinqKit制作可重用的Linq-to-Entities表达式

时间:2018-06-22 10:54:18

标签: c# entity-framework-6 linq-to-entities linqkit

假设我有一个表Foo与表Bar有一对多关系。

这两个表都有很多列,因此当我使用EntityFramework来获取它们时,我只想选择需要填充适当的DTO的列。

Expression<Func<BAR, BarDto>> BarToDto()
{
    return T => new BarDto(){
        Id = T.id,
        Text = T.text
    }
}

using (ModelContainer m = new ModelContainer())
{
    var returnVal = m.BAR.Select(BarToDto()).ToList();
}

现在,当我选择表单Foo时,我还想选择关联的Bar行,所以我将使用类似的东西:

Expression<Func<FOO, FooDto>> FooToDto()
{
    return T => new FooDto(){
        Id = T.id,
        Text = T.text,
        Bars = T.BAR.Select(B => new BarDto(){
            Id = B.id,
            Text = B.text
        }).ToList()
    }
}

using (ModelContainer m = new ModelContainer())
{
    var returnVal = m.FOO.Select(FooToDto()).ToList();
}

但是我一直在尝试重用BarToDto()表达式中的代码,最终发现LinqKit

通过阅读LinqKit GitHub指令,它说您应该在查询的表上使用.AsExpandable(),然后可以在另一个表中调用该表达式:

T.BAR.Select(BarToDto().Compile()).ToList()

因为根据LinqKit GitHub页面:

  

编译实际上从未运行; LINQ to SQL或Entity Framework也从未看到过它。通过调用AsExpandable创建的特殊包装将对Compile的调用完全剥离,并替换为正确的表达式树。

给出的另一种选择是直接在我们要使用的表达式上使用.Expand()

T.BAR.Select(BarToDto().Expand().Compile()).ToList()

而不是使用.AsExpandable(),但是事实是,这两种方法都导致一个Internal .NET Framework Data Provider error 1025.,如果我使用.Compile()(并且将Expression>变成没有LinqKit的Func <>)。

后来,我在此站点上发现an answer,说我需要在调用.Invoke()之前将表达式分配给局部变量,如下所示:

Expression<Func<FOO, FooDto>> FooToDto()
{
    var BarExpr = BarDto();

    return T => new FooDto() 
    {
        Id = T.id,
        Text = T.text,
        Bars = T.BAR.Select(b => BarExpr.Invoke(b)).ToList()
    }
}

但这反过来会导致LINQ to Entities does not recognize the method 'BarDto Invoke[BAR,BarDto](System.Linq.Expressions.Expression´1[System.Func´2[BAR,BarDto]], BAR)' method, and this method cannot be translated into a store expression.

是否有必要在ModelContainer中进行某些配置以使用LinqKit扩展方法,还是类似这样的应用程序超出了LinqKit的功能?

0 个答案:

没有答案