c# - 用于获取包含 SQL IN() 的 EF 的 LINQ 的表达式,其中实体子属性等于值

标签 c# entity-framework linq entity-framework-core

我有一个简单的需要,即从返回的集合中过滤出所有父项,其中在字段上没有匹配项,从字符串中按名称调用,与显示的值不匹配。我追求的是 if 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 try

//...
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 向后工作。我想我很接近,但很难用输出来判断。我把它放在这里以供引用。需要明确的是, child 的属性名称将是名称的字符串。最好的结果是我可以有一个像 udfs.foo 这样的名字如果值包含字符串名称,我可以在任何级别上进行测试,但从这里开始真的没问题,

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

output of 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)));

关于c# - 用于获取包含 SQL IN() 的 EF 的 LINQ 的表达式,其中实体子属性等于值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55290649/

相关文章:

c# - 如何将MemoryStream写入文本文件的末尾

c# - 生成可以将两个字符串连接在一起的 C# 表达式

c# - 使用 MVC 3 Entity Framework 代码优先,如何在一对多关系中创建一个新的 "many"对象?

visual-studio - 用于 VS 2010 的 LINQ to SQL 可视化工具?

vb.net - Linq Select withWhere 基于下拉值

c# - 如何将datagridview列更改为int

c# - 公共(public)语言运行时检测到无效程序?

c# - 从 Clearcase 的动态 View 将自定义控件 dll 添加到 Visual Studio 工具箱

c# - EntityState.Modified 在实体代码优先中不起作用

c# - 对 MongoDb 和 Entity Framework 的抽象