为LINQ TO实体编写可翻译的方法

时间:2018-01-29 08:55:09

标签: c# entity-framework linq linq-to-entities expression

使用实体框架(LINQ to Entities)

以下工作正常。表达式已转换为SQL

var foos = ctx.Foos.Select(f => new {
   P1 = ctx.Bars.FirstOrDefault(b => b.SomeProp == "Const1" && f.X1 == b.Y),
   P2 = ctx.Bars.FirstOrDefault(b => b.SomeProp == "Const2" && f.X2 == b.Y),
   P3 = ctx.Bars.FirstOrDefault(b => b.SomeProp == "Const3" && f.X3 == b.Y),
}

重复表达式b.SomeProp == "..." && f.X* == b.Y实际上是真实表达式的简化版本,但是如果你可以帮我理解这一点。我也会弄清楚剩下的......

我想写的是这样的。 (首选)

var foos = ctx.Foos.Select(f => new {
   P1 = f.GetBar("Const1", f.X1),
   P2 = f.GetBar("Const2", f.X2),
   P3 = f.GetBar("Const3", f.X3),
}

但我可能也会喜欢

P1 = ctx.Bars.GetByFoo(f.X1, "Const1");
- or -
P1 = ctx.Bars.FirstOrDefault(GetByFoo(f.X1, "Const1"))
- or -
P1 = ctx.Bars.GetByFoo(x => x.X1, "Const1");

基于这个答案https://stackoverflow.com/a/2244917/2968001我到目前为止最接近的是

ctx.Bars.FirstOrDefault(GetByFoo(x => x.Y == f.X1 , "Const1"))

and

private static Expression<Func<Bar, bool>> GetByFoo(Func<Foo, bool> optionSelector, string par1)
    {
        return b => b.SomeProp == par1 && optionSelector(o);
    }
不幸的是,这个 a)仍然很不理想 b)这不起作用:(。它给出了运行时异常:

  

从范围''引用的'Foo'类型的变量'f',但它不是   定义

表达式必须保持可翻译。检索所有的foos然后为每个foo检索Bar都不行。

1 个答案:

答案 0 :(得分:0)

这些方面的内容如何

public static class Extensions
{
    public static IQueryable<T> Filter<T>(this DemoContext instance, Expression<Func<T, bool>> predicate = null, string value = null)
        where T : class, IMarker
    {
        return instance
            .Set<T>()
            .Where(p => p.SomeProp == value)
            .Where(predicate);
    }
}

应该允许你写一些类似

的东西
var inner1 = ctx.Filter<Bar>(value: "Const1");
var inner2 = ctx.Filter<Bar>(value: "Const2");
var inner3 = ctx.Filter<Bar>(value: "Const3");

var query = from foo in ctx.Foos
            select new
            {
                P1 = inner1.FirstOrDefault(p => p.Y == foo.X1),
                P2 = inner2.FirstOrDefault(p => p.Y == foo.X2),
                P3 = inner3.FirstOrDefault(p => p.Y == foo.X3),
            };

其中IMarker接口只是为了帮助您处理专门的谓词

public class Foo : IEntity
{
    public string X1 { get; set; }
    public string X2 { get; set; }
    public string X3 { get; set; }

}

public class Bar : IMarker
{
    public string SomeProp { get; set; }
    public string Y { get; set; }
}

public interface IEntity
{
}

public interface IMarker : IEntity
{
    string SomeProp { get; set; }
}