如何在不获取对象,更改对象和调用SaveChanges的情况下在LINQ中编写UPDATE?

时间:2016-05-29 20:55:59

标签: c# entity-framework linq

我正在寻找一个等同于:

的LINQ查询
UPDATE Person p SET p.Age = p.Age + 1 WHERE p.Id = 123

我知道解决方案是选择行然后更新它:

var p = db.Set<Person>.Where(p => p.Id==123);
p.Age = p.Age + 1;
db.SaveChanges();

但这不是一种安全的方式,因为在提交更改之前,某人可能会增加Age的值,而我们会用错误的值覆盖该值。

问题:是否有能够转换为更新查询的LINQ查询:

UPDATE Person p SET p.Age = p.Age + 1 WHERE p.Id = 123

3 个答案:

答案 0 :(得分:2)

据我所知,你不能在默认的实体框架中使用LINQ,所以你有的选择是:

  1. 在这种情况下,只需使用原始SQL查询并忘记LINQ和Entity Framework。
  2. 尝试使用EntityFramework.Extended库。它有Update扩展方法,因此在您的情况下将是:

    db.Set<Person>.Where(p => p.Id==123).Update(p => new Person {Age = p.Age + 1});
    

    这个库的作用是解析表达式树并构造原始更新sql查询到你的数据库。对于简单的情况,它应该可以正常工作(当然,由它生成的sql并不像你自己编写的那样干净,但对于EF本身也是如此)。

答案 1 :(得分:1)

这不是Linq方法,但您可以通过以下方式发出查询:

 var incrementStep = 1;
 var personId = 123;
 db.Database.ExecuteSqlCommand("UPDATE Person p SET p.Age = p.Age + @p0 WHERE p.Id = @p1",
                                incrementStep, personId);

处理场景的另一种方法是通过行版本列处理乐观并发,该列跟踪上次更改行的时间(有关更完整的示例和说明,请参阅this文章)。

答案 2 :(得分:1)

如果我没有记错,你需要悲观的逻辑来处理EF中的这种情况。 我知道的一种方法是使用包含锁定提示的SQL语句从上下文加载对象(并在事务中执行)。

但是为了处理这种情况,我通常会使用存储过程并绕过ORM。