jer*_*ass 3 c# linq entity-framework entity-framework-core
我有一个简单的需要从返回的集合中过滤掉所有父项,其中字段上没有匹配项,即从字符串中按名称调用,与呈现的值不匹配。我所追求的是,如果parent对象有child对象,并且child对象属性"foo"(由字符串调用)不或不等于 value 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`
Run Code Online (Sandbox Code Playgroud)
我希望看到的是类似于 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
Run Code Online (Sandbox Code Playgroud)
我处理这个问题的方法是设置一个表达式来获取List<string>并生成 SQL。我已经阅读了近 50 篇文章和 SO 帖子,但还没有弄清楚为什么我还没有得到这个,因为每个人似乎都有不同的想法,而且大多数似乎都不符合 dotnet core 2.1+。
这是我经过多次迭代后目前所坐的。注意:它与我所追求的略有不同,因为我正在提供我目前的线索。
我当前的上下文 linq 尝试
//...
dataPage = dataPage.Where(DbHelper.byPropertyContains<ae_s_bld_c>("udfs", field, values));
//...
Run Code Online (Sandbox Code Playgroud)
我认为这将是更好的,如果它就像我竖起了第一个例子,但是这是我已经登陆,因为我有一个时间排队它了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);
}
}
Run Code Online (Sandbox Code Playgroud)
根据@NetMage 的要求,我尝试使用 LINQpad 向后工作。我想我很接近,但很难用输出来判断。我把它放在这里以供参考。需要明确的是,孩子的属性名称将是名称的字符串。最好的结果是我可以有一个名字udfs.foo,如果值包含字符串名称,我可以在任何级别上进行测试,但从这里开始真的没问题,
var result = dataPage.Where(x =>
DbHelper.byPropertyContains(x.udfs, field, values)
);
Run Code Online (Sandbox Code Playgroud)
让我们从这里开始。你需要一个类似这样的东西
var result = dataPage.Where(x => values.Contains(x.udfs.{field}));
Run Code Online (Sandbox Code Playgroud)
其中field是返回由名称动态指定的属性的字符串。
在 EF Core 中,您甚至不需要手动处理构建表达式,因为 EF Core 提供了一个特殊的 SQL 可翻译函数,用于通过名为EF.Property的名称访问简单属性。
使用该方法,解决方案很简单:
var result = dataPage
.Where(x => values.Contains(EF.Property<string>(x.udfs, field)));
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3637 次 |
| 最近记录: |