【问题标题】:Perform mutable updates in LINQ query?在 LINQ 查询中执行可变更新?
【发布时间】:2009-09-25 13:51:26
【问题描述】:

我有一个 LINQ 查询,我想在其中返回修改后的对象。如果我处于一种不变的函数式情绪中,我可能会做一些类似于复制构造器的事情,如下所示:

from widget in widgets select new widget { legs = widget.legs + 1, arms = widget.arms }

遗憾的是,我在一个可变的 NHibernate 实体对象上执行此操作,我必须修改原始对象。我正在寻找一些带有副作用的匿名方法的语法,例如:

from widget in widgets select { widget.legs += 1; return widget }

(对 Scala 语法表示歉意)

现在,我可以在 LINQ 查询之外执行此更新,但如果可以的话,我宁愿内联进行。是否可以在LINQ中插入void之类的操作?

【问题讨论】:

  • 我认为在查询中进行变异是一个糟糕的主意。我认为 Eric Lippert 在本网站的其他地方写了一些语句,以在语句中进行突变,并保持你的表达没有副作用。表达式应该是可组合的,而副作用会杀死它。
  • 是的,我原则上同意你的看法。也许我试图在查询中做太多事情。问题是,我只是在做我本来会用投影做的事情。唯一的区别是我使用的是实体而不是值对象,并且该对象的身份是代理项,因此值必须发生变化(而不是处理我将投影到另一个值对象的值对象)身份不同)。但是你关于突变的观点仍然成立。
  • 在基于集合的操作中改变查询是完全可以接受的事情。唉,LINQ 还没有。

标签: c# linq nhibernate


【解决方案1】:
widgets
.ToList()
.Select(widget => 
{
  widget.legs +=1;
  return widget
})
.ToList()

ToList 将枚举(运行)查询。

编辑,我插入了第二个 ToList 以允许使用 Enumerable.Select 而不是 Queryable.Select 。

您表明您希望 NHibernate 运行代码....意识到查询翻译器满足您的要求,但不是您的文字说明。

from old in widgets
select new widget() {legs = old.legs + 1, arms = old.arms}

查询翻译器应该将投影发送到数据库中,而不是新建 2 个小部件。

【讨论】:

  • 当我尝试这样做时,编译器会说“无法将带有语句体的 lambda 表达式转换为表达式树”。也许这只适用于 LINQ to Objects?我想要一些适用于 LINQ to NHibernate 的东西。另外:我将如何使用 LINQ 而不是 lambda 语法来做到这一点?
  • 这不会和他的第一个例子“legs = widget.legs + 1”有相同的结果吗?
  • 我的第一个示例是创建新对象的复制构造函数。 David B 的示例将更新对象(这是我想要实现的)。
  • .NET 3.5/C# 3 中的表达式树不支持语句,这反过来意味着不能用于生成 SQL。 (这也是 VB 没有 lambda 语句的原因。)这应该在 .NET 4/C# 4/VB 10 中得到修复。
  • 感谢您的回答,Grauenwolf。这解释了很多。感谢 David B。我接受您的回答,因为它是最接近的解决方案!
猜你喜欢
  • 2018-05-08
  • 1970-01-01
  • 1970-01-01
  • 2019-07-16
  • 1970-01-01
  • 1970-01-01
  • 2018-02-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多