【问题标题】:only update 1 column with linq仅使用 linq 更新 1 列
【发布时间】:2009-07-23 14:38:19
【问题描述】:

我正在使用 linq 从数据库中的表中检索一行。 现在我只更新 1 列。 然后我将它更新回数据库。

一切顺利,除了其他任何字段被另一个进程/线程/用户更改的时候 在那种情况下,我得到一个异常(乐观并发),告诉我要注意,自从我上次使用 linq 获取对象以来,值已经改变了。

由于我只对这 1 列感兴趣,我可以告诉 linq 只更新此列而忽略其他列吗? (并警告我这一栏确实已更改)

R

【问题讨论】:

    标签: sql linq concurrency


    【解决方案1】:

    您可以通过发送ChangeConflictException 来检测并解决并发问题:

    using (var db = new MyDataContext())
    {
        var row = db.MyTable.Single(x => x.Id == tableId);  // Getting the row
    
        row.Column = columnNewValue;  // Assign the new value
    
        try
        {
            db.SubmitChanges();
        }
        catch (ChangeConflictException)
        {
            db.ChangeConflicts.ResolveAll(RefreshMode.KeepChanges);
            db.SubmitChanges();
        }
    }
    

    使用RefreshMode.KeepChanges,对您的客户端对象所做的所有更改都将保留,其他用户/进程/线程对其他列的更改将被合并。

    在您的情况下,只会更改您的列。

    推荐文章:

    【讨论】:

    • 嗨...我认为'keepchanges'会支持我的对象的任何值,而不是数据库中的值。但正如你所说,我现在正在阅读,只有我的对象中更改的值比数据库值更受青睐。太好了!
    • 如果行需要被两个或多个值选中怎么办?我怎么写那个“哪里”?
    【解决方案2】:

    我不太了解这一点,但看起来您可以使用 ColumnAttribute 上的 UpdateCheck.Never 枚举值来完全避免并发检查。

    MSDN

    【讨论】:

    • 我对并发检查没问题...但仅在我更新的 1 列上。使用 Linq,似乎总是对所有列进行更新(这在大多数情况下都很好)。
    • 我想我误读了你的答案......你是说'每列'你可以设置并发检查开/关?这正是我正在寻找的
    【解决方案3】:

    MSDN上有一篇不错的文章:

    Simultaneous Changes

    下面的例子(在文章中更进一步)可能会引起特别的兴趣:

    public partial class Northwind : DataContext
    {
       ...
    
       public void UpdateProduct(Product original, Product current) {
          // Execute the stored procedure for UnitsInStock update
          if (original.UnitsInStock != current.UnitsInStock) {
             int rowCount = this.ExecuteCommand(
                "exec UpdateProductStock " +
                "@id={0}, @originalUnits={1}, @decrement={2}",
                original.ProductID,
                original.UnitsInStock,
                (original.UnitsInStock - current.UnitsInStock)
             );
             if (rowCount < 1)
                throw new Exception("Error updating");
          }
          ...
       }
    }
    

    你的存储过程是:

    create proc UpdateProductStock
       @id               int,
       @originalUnits    int,
       @decrement         int
    as
    UPDATE Product 
    SET originalUnits=@originalUnits,
        decrement=@decrement
    WHERE id=@id
    

    根据我的经验,最好的方法是制作自己的存储过程。除非您将(几乎)所有列中的“UpdateCheck”属性设置为“从不”,否则 Linq 并没有提供一种简单的方法来进行同时更改。

    【讨论】:

    • 是的...人们总是可以求助于存储过程,或者只是原始的 sql 语句。但是,我认为 linq 会为我抽象出来。
    【解决方案4】:

    听起来您可能正在以单例模式使用 DataContext,或者至少在多个线程之间共享它。

    当您在 DataContext 上调用 SubmitChanges 时,将执行 DataContext 知道的所有数据库更改。

    DataContext 旨在仅用作工作单元对象,并在您完成该工作后立即处置。

    【讨论】:

    • 嗨,这根本不是我的意思。其他程序也可以访问数据库。这就是为什么我得到这个例外。我只是说:我只对更新其中一个列值感兴趣……在此期间任何其他列已更新与我无关……但是,linq 检查所有列以查看它们是否仍然存在一样的。
    【解决方案5】:

    我找到了this。这就是你要找的吗?

    如果这不能解决问题,您可以随时构建 sql 更新语句并执行它。

    【讨论】:

      【解决方案6】:

      您可以这样做,但这需要您以某种方式构建代码。

      例如,您有需要单独更新的描述和金额。然后,您将创建 2 个方法:

      • updateAmount 接受密钥和金额。
      • udateDesription 包含密钥和描述。

      然后在例如更新金额方法内:

      • 创建可序列化事务
      • 从数据库中读取行
      • 更新了内存中的数量
      • 将记录保存到数据库中
      • 提交事务

      当您这样做时,您只会更改您打算更改的内容。

      我们使用这种模式的时间是由于审计要求。您可以说该用户更改了金额并且该用户更改了描述。并不是说每个用户都更改了记录,您需要查看数据以了解他们做了什么。

      【讨论】:

      • 添加事务会增加锁并降低速度。这两件事我都不想要。
      【解决方案7】:

      我阅读了一篇文章,讨论了在运行时更改 UpdateCheck 属性的可能性。 (将它归档在“我可能有一天会需要”类别下,但到目前为止我还不需要它。)

      http://mtaulty.com/CommunityServer/blogs/mike_taultys_blog/archive/2007/12/20/10038.aspx

      【讨论】:

      • 哇...这似乎是一种过于复杂的方法。奇怪的是可以在设计时设置它,但不能在运行时设置(或者,至少不能用很多魔法)。
      【解决方案8】:

      如果您有权更改数据库架构,请将时间戳列添加到相关数据表中,然后确保没有为并发更新设置其他列(它应该自动选择时间戳列,但可能需要如果没有,请在您的 dbml 中重新生成表)。当您有 TimeStamp 列时,LINQ to SQL 将仅在进行并发检查时使用该字段,从而允许更离散的更新。

      【讨论】:

        【解决方案9】:

        使用http://plinqo.com 的 PLINQO 框架,如果您喜欢使用作为 PLINQO 一部分的批处理操作,您可以更新一列。

        context.Task.Update(t => t.Id == 1, t2 => 新任务 {StatusId = 2});

        这将执行更新任务集 StatusId = 2 where Id = 1

        【讨论】:

          猜你喜欢
          • 2015-10-05
          • 1970-01-01
          • 2016-08-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多