【问题标题】:EF Core Update updates all columns even though only one has changedEF Core Update 更新所有列,即使只有一列发生了变化
【发布时间】:2020-03-28 19:03:37
【问题描述】:

我对使用 EF Core 有点陌生。据我了解,EF Core 有一个“更改跟踪器”,它查看数据以查看哪些列已被修改并构建一个仅更新修改后的列的 SQL UPDATE 语句,如此处的答案所述:

Does EF core compares value to include columns in update statement?

但是,这不是我所看到的。例如,我有这个实体:

public class Book
{
    public int BookId { get; set; }
    [StringLength(255)]
    public string Title { get; set; }
    public int AuthorId { get; set; }
    public Author Author { get; set; }
    [StringLength(500)]
    public string Description { get; set; }
}

然后我使用以下代码更新现有行:

class Program
{
    static void Main(string[] args)
    {
        var context = new TestContext();
        var book = context.Books.Find(1);
        book.Title += " x";
        context.Books.Update(book);
        context.SaveChanges();
    }
}

我启动了 SQL Profiler 并运行了这段代码。我希望看到只更新“标题”列的 UPDATE 语句,但它总是更新每一列:

exec sp_executesql N'SET NOCOUNT ON;
UPDATE [Books] SET [AuthorId] = @p0, [Description] = @p1, [Title] = @p2
WHERE [BookId] = @p3;
SELECT @@ROWCOUNT;
',N'@p3 int,@p0 int,@p1 nvarchar(500),@p2 nvarchar(255)',@p3=1,@p0=1,@p1=N'',@p2=N'Some Title x'

例如,列 Description 未更改,但它在 UPDATE 语句中,就像 AuthorId 一样。

这是为什么呢?它不应该只是在 SET 子句中有 Title 吗?

【问题讨论】:

  • 你不需要更新那一行。你认为你为什么需要它?
  • 认为您需要调用 update 是一个常见的错误,但在这种情况下它不是必需的,实际上是导致您的问题的原因。以下是对差异的简单描述。 learnentityframeworkcore.com/dbcontext/modifying-data
  • 谢谢,就这样!我知道它一定是我忽略的东西。 @ErikEJ,它在我找到的一些示例代码中。
  • 不要相信你在互联网上找到的东西!

标签: c# entity-framework-core


【解决方案1】:

据我了解,EF Core 有一个“更改跟踪器”

这是正确的,这就是为什么一旦将实体附加到上下文中,您就可以免于将它们标记为已更新。行后...

book.Title += " x";

...EF 检测到此更改并将标记Title 标记为已修改。无需调用Update 方法。

这就是所谓的“连接”场景。

Update 方法适用于disconnected scenario。那时实体对象未附加到上下文,但其值应保存到数据库中,例如,在 Web API 后端中。基本形式:

public void SaveBook(Book book)
{
    // Here, 'book' is the book with the changed Title.
    using(var context = new TestContext())
    {
        context.Books.Update(book);
        context.SaveChanges();
    }
}

现在,EF 无法检测到更改,因为book 在进入方法时已被修改。你必须告诉 EF 这本书必须更新。但是 EF 不知道修改了什么;它所能做的最好的就是将所有属性(除了主键)标记为已修改。

但是,仍然可以通过将断开连接的场景转换为连接的情况来使 EF 仅更新实际更新的属性:

public void SaveBook(Book book)
{
    // Here, 'book' is the book with the changed Title.
    using(var context = new TestContext())
    {
        var dbBook = context.Books.Find(book.ID);

        // Copy book's property values to dbBook.
        context.Entry(dbBook).CurrentValues.SetValues(book);

        context.SaveChanges();
    }
}

可能有good reasons更喜欢后者而不是前者。

【讨论】:

    【解决方案2】:

    在您的连接场景中,您不需要调用 Update 方法。

    【讨论】:

      猜你喜欢
      • 2017-11-11
      • 1970-01-01
      • 2020-08-23
      • 2018-04-21
      • 1970-01-01
      • 1970-01-01
      • 2020-09-23
      • 2016-01-30
      相关资源
      最近更新 更多