将多个相似的 SELECT 表达式组合成一个表达式
如何将多个相似的 SELECT 表达式组合成一个表达式?
private static Expression<Func<Agency, AgencyDTO>> CombineSelectors(params Expression<Func<Agency, AgencyDTO>>[] selectors)
{
// ???
return null;
}
private void Query()
{
Expression<Func<Agency, AgencyDTO>> selector1 = x => new AgencyDTO { Name = x.Name };
Expression<Func<Agency, AgencyDTO>> selector2 = x => new AgencyDTO { Phone = x.PhoneNumber };
Expression<Func<Agency, AgencyDTO>> selector3 = x => new AgencyDTO { Location = x.Locality.Name };
Expression<Func<Agency, AgencyDTO>> selector4 = x => new AgencyDTO { EmployeeCount = x.Employees.Count() };
using (RealtyContext context = Session.CreateContext())
{
IQueryable<AgencyDTO> agencies = context.Agencies.Select(CombineSelectors(selector3, selector4));
foreach (AgencyDTO agencyDTO in agencies)
{
// do something..;
}
}
}
How to combine several similar SELECT-expressions into a single expression?
private static Expression<Func<Agency, AgencyDTO>> CombineSelectors(params Expression<Func<Agency, AgencyDTO>>[] selectors)
{
// ???
return null;
}
private void Query()
{
Expression<Func<Agency, AgencyDTO>> selector1 = x => new AgencyDTO { Name = x.Name };
Expression<Func<Agency, AgencyDTO>> selector2 = x => new AgencyDTO { Phone = x.PhoneNumber };
Expression<Func<Agency, AgencyDTO>> selector3 = x => new AgencyDTO { Location = x.Locality.Name };
Expression<Func<Agency, AgencyDTO>> selector4 = x => new AgencyDTO { EmployeeCount = x.Employees.Count() };
using (RealtyContext context = Session.CreateContext())
{
IQueryable<AgencyDTO> agencies = context.Agencies.Select(CombineSelectors(selector3, selector4));
foreach (AgencyDTO agencyDTO in agencies)
{
// do something..;
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
不简单;你需要重写所有表达式 - 严格来说,你可以回收其中的大部分表达式,但问题是每个表达式都有不同的
x
(即使它看起来相同),因此你需要使用访问者将所有参数替换为finalx
。幸运的是,这在 4.0 中还不算太糟糕:它使用找到的第一个表达式中的构造函数,因此您可能想要健全性检查所有其他表达式是否在各自的 NewExpression 中使用了简单的构造函数 。不过,我已经把这个留给读者了。
编辑:在评论中,@Slaks 指出更多的 LINQ 可以使这个时间更短。他当然是对的——不过为了便于阅读,有点晦涩难懂:
Not simple; you need to rewrite all the expressions - well, strictly speaking you can recycle most of one of them, but the problem is that you have different
x
in each (even though it looks the same), hence you need to use a visitor to replace all the parameters with the finalx
. Fortunately this isn't too bad in 4.0:This uses the constructor from the first expression found, so you might want to sanity-check that all of the others use trivial constructors in their respective
NewExpression
s. I've left that for the reader, though.Edit: In the comments, @Slaks notes that more LINQ could make this shorter. He is of course right - a bit dense for easy reading, though:
如果所有选择器仅初始化
AgencyDTO
对象(如您的示例),您可以将表达式转换为NewExpression
实例,然后调用Expression.New
以及表达式的Members
。您还需要一个
ExpressionVisitor
,将原始表达式中的ParameterExpression
替换为您要创建的表达式的单个ParameterExpression
。If all of the selectors will only initialize
AgencyDTO
objects (like your example), you can cast the expressions toNewExpression
instances, then callExpression.New
with theMembers
of the expressions.You'll also need an
ExpressionVisitor
to replace theParameterExpression
s from the original expressions with a singleParameterExpression
for the expression you're creating.万一其他人偶然发现了与我类似的用例(我根据所需的详细程度选择了不同的目标类):
简化的场景:
我调整了 @Marc Gravell 提供的解决方案,如下所示:
Map<扩展类的 /code> 方法则变为:
In case anyone else stumbles upon this with a similar use case as mine (my selects targeted different classes based on the level of detail needed):
Simplified scenario:
I adapted the solution provided by @Marc Gravell like so:
The
Map
method of the extended class then becomes: