LINQ - 按属性名称选择
Posted
技术标签:
【中文标题】LINQ - 按属性名称选择【英文标题】:LINQ - select by property name 【发布时间】:2020-11-03 04:00:57 【问题描述】:我有以下课程:
public class User
public string userName get; set;
public bool active get; set;
示例:
userName: John,
active: true
,
userName: Mary,
active: true
如何通过属性名称查询“活跃”用户? 这是我尝试过的,但我得到了:
“无法翻译 LINQ 表达式 ...。要么以可翻译的形式重写查询,要么通过插入对 AsEnumerable()、AsAsyncEnumerable() 的调用显式切换到客户端评估, ToList() 或 ToListAsync()"
Type t = typeof(User);
PropertyInfo p = t.GetProperty("active");
int totalActive = userContext.Users.Where(u => Convert.ToBoolean(p.GetValue(u)) == true).Count();
【问题讨论】:
你不知道编译时属性的名称吗?这是为什么?无论如何,客户评估应该按照消息的建议进行(例如,userContext.Users.ToList().Where(...)
)。
第一个 active
不是属性...它是一个字段。 GetProperty
找不到。第二...为什么u
和t
是同一类型时需要反射。
@LegacyCode - 嗯,它是一个自动属性。
@MineKrafter 这不是我回复它的时候。 janzen 将其更改为自动属性。
【参考方案1】:
如果由于某种原因您需要动态执行此操作,则需要手动构建 expression tree(检查 Queryable.Where
签名):
public class User
public string userName get;set;
public bool active get;set;
Type t = typeof(User);
PropertyInfo p = t.GetProperty("active");
var prmtr = Expression.Parameter(t);
var value = Expression.Constant(true);
var comprasion = Expression.Equal(Expression.Property(prmtr, p), value);
var expr = Expression.Lambda<Func<User, bool>>(comprasion, prmtr);
int totalActive = userContext.Users.Where(expr).Count();
【讨论】:
【参考方案2】:正如错误所说,您需要在尝试过滤 Where 子句中的数据之前调用 AsEnumerable()。
Type t = typeof(User);
PropertyInfo p = t.GetProperty("active");
int totalActive = userContext.Users.AsEnumerable().Where(u => Convert.ToBoolean(p.GetValue(u)) == true).Count();
这是因为 linq 将尝试将您的表达式转换为 sql 查询,并且您在 where 语句上使用了一个函数,linq 将无法转换此表达式,因为该函数在 sql 上不存在。
AsEnumerable() 将强制查询运行并将数据拉入内存,然后 c# 将应用过滤。
【讨论】:
我会非常犹豫是否将其用于数据库,特别是如果 Users 表有大量行..【参考方案3】:int totalActive = userContext.Users.Where(u => u.active).Count();
【讨论】:
【参考方案4】:这是一个关于Client vs. Server Evaluation的问题。
因为你在where条件中使用了一些sql server端无法识别的方法,所以可以将当前的linq全部转换到客户端执行。
即添加 AsEnumerable()
或 ToList()
到 userContext.Users
。
例子:
int totalActive = userContext.Users.AsEnumerable().Where(u => Convert.ToBoolean(p.GetValue(u)) == true).Count();
另外一种方式,你也可以将所有的linq语句转换成sql server-side认可的语句来执行,正如上面@Guru Stron提供的答案。
【讨论】:
以上是关于LINQ - 按属性名称选择的主要内容,如果未能解决你的问题,请参考以下文章