Write a translatable method for LINQ TO Entities

和自甴很熟 提交于 2019-12-24 18:43:04

问题


Using Entity Framework (LINQ to Entities)

The following is working just fine. The expressions got translated to 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),
}

The repetitive expression b.SomeProp == "..." && f.X* == b.Y is actually a simplified version of the real expression, but if you can help me wit this. I'll figure out the rest as well...

What I would like to write is something like this. (Preferred)

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),
}

But I might also be fine with something like

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");

Based on this answer https://stackoverflow.com/a/2244917/2968001 The closest I came so far is

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);
    }

Unfortunately, this a) Is still far from desired b) this does not work :(. It gives a run-time exception:

variable 'f' of type 'Foo' referenced from scope '', but it is not defined

It is essential that the expression keeps translatable. I am not fine with retrieving all foos and then retrieving the Bar for each foo.


回答1:


how about something along these lines

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);
    }
}

that should allow you to write something like

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),
            };

where the IMarker interface is just to help you deal with specialized predicates

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; }
}


来源:https://stackoverflow.com/questions/48497487/write-a-translatable-method-for-linq-to-entities

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!