繁体   English   中英

使用包含到 EF for SQL IN() 的表达式获取 LINQ,其中实体上的子属性等于值

[英]Expression to get LINQ with Contains to EF for SQL IN() where on entities child's property equals value

我有一个简单的需要,从返回的集合中过滤掉所有父项,其中字段上没有匹配项,即从字符串中按名称调用,与呈现的值不匹配。 我所追求的是,​​如果parent对象具有child对象,并且该child对象属性"foo" (由字符串调用)不等于或等于值bar ,则从集合中适当地过滤parent对象。

这是我的 linq ef 电话

var field = "bar";
var values = new List<string>{"foo","fuYu"};
var dataPage = _aim_context.ae_s_bld_c.AsNoTracking();
var result = dataPage.Where(x => 
                              DbHelper.byPropertyContains(x.udfs, field, values)
                           );
// NOTE `udfs` is a ONE-to-ONE with `ae_s_bld_c`

我希望看到的是类似于 SQL 的东西

SELECT [m].[id],[m.udfs].[bar],
FROM [dbo].[ae_s_bld_c] AS [m]
    INNER JOIN [dbo].[ae_s_bld_c_udf] AS [m.udfs]
        ON ([m].[multitenant_id] = [m.udfs].[multitenant_id])
WHERE ([m].[multitenant_id] = 1.0)
    AND ([m.udfs].[bar] IN ('foo','fuYu')) --< Goal line

我处理这个问题的方法是设置一个表达式来获取List<string>并生成 SQL。 我已经阅读了近 50 篇文章和 SO 帖子,但还没有弄清楚为什么我还没有得到这个,因为每个人似乎都有不同的想法,而且大多数似乎都不符合 dotnet core 2.1+。

这是我经过多次迭代后目前所坐的。 注意:它与我所追求的略有不同,因为我正在提供我目前的线索。

我当前的上下文 linq 尝试

//...
dataPage = dataPage.Where(DbHelper.byPropertyContains<ae_s_bld_c>("udfs", field, values));
//...

我认为如果它像我提出的第一个例子会更好,但这就是我已经登陆的原因,因为我有时间将它与x=>x.udfs ,两者都是x=> funName(x.udfs)x=> x.udfs.funName()

我构建表达式的静态方法

public static class DbHelper
{
    public static Expression<Func<T, bool>> byPropertyContains<T>(string node, string field, List<string> value) {
//trying to take parent item and get it's property by string name because
// doing the function in linq like x=>x.udfs was not working right
// but that is the prefered I think
        var property_parameter = Expression.Parameter(typeof(T), "x");
        var property = Expression.PropertyOrField(property_parameter, node);
        var selector_parameter = Expression.Parameter(property.Type, "y");
        var selector = Expression.PropertyOrField(selector_parameter, field);
        var methodInfo = typeof(List<string>).GetMethod("Contains", new Type[] {
            typeof(string)
        });
        var list = Expression.Constant(value, typeof(List<string>));
        var body = Expression.Call(methodInfo, list, selector);
        return Expression.Lambda<Func<T, bool>>(body, selector_parameter);
    }
}

更新

根据@NetMage 的要求,我尝试使用 LINQpad 向后工作。 我想我很接近,但很难用输出来判断。 我把它放在这里以供参考。 需要明确的是,孩子的属性名称将是名称的字符串。 最好的结果是我可以有一个像udfs.foo这样的名称,如果值包含字符串名称,我可以在任何级别上进行测试,但从这里开始真的没问题,

var result = dataPage.Where(x => 
                              DbHelper.byPropertyContains(x.udfs, field, values)
                           );

LINQpad的输出

让我们从这里开始。 你需要一个类似这样的东西

var result = dataPage.Where(x => values.Contains(x.udfs.{field}));

其中field是一个字符串,返回由名称动态指定的属性。

在 EF Core 中,您甚至不需要手动处理构建表达式,因为 EF Core 提供了一个特殊的 SQL 可翻译函数,用于通过名为EF.Property的名称访问简单属性。

使用该方法,解决方案很简单:

var result = dataPage
   .Where(x => values.Contains(EF.Property<string>(x.udfs, field)));

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM