我有一个简单的需要,即从返回的集合中过滤出所有父项,其中在字段上没有匹配项,从字符串中按名称调用,与显示的值不匹配。我追求的是 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)
);
最佳答案
让我们从这里开始。你需要类似这样的东西
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/