c# - EF Core 修改后的实体状态如何表现?

标签 c# entity-framework-core ef-core-2.2

我们把实体 state = modified 在更改之后或更改之前是否重要?

using (var db = new LakshyaContext())
{
    foreach (var category in db.Categories)
    {
        db.Entry(category).State = EntityState.Modified; // before
        category.Count = 25; //Making Changes
        db.Entry(category).State = EntityState.Modified; //After
    }

    db.SaveChanges();
}

最佳答案

所以首先,让我们解决最重要的事情:
你是对的。在您的示例中,您不需要手动调用 db.Entry(category).State = EntityState.Modified 。这是因为您正在从上面的上下文加载条目(类别)。这被称为“连接场景”,其中 DbContext 知道实体,它是 跟踪它们 。这是相同的,例如在 ASP.NET Core 应用程序中,上下文在 HTTP 请求之间共享。
当您调用 using (var db = new LakshyaContext()) 时,您在 SaveChanges 范围内所做的任何修改都会被上下文知道。
现在,在处理断开连接的场景时(如您所说的 UnTracked 实体),我们必须更深入地挖掘。
要理解这一点,首先您需要知道 DbContext 如何知道发生了什么变化。以下面的例子为例:

using (var context = new MyContext())
{
    // loads the book by it's ISBN
    var book = context.Books
        .Single(p => p.ISBN == "123456");
    
    // Do changes
    book.Price = 30;
    
    // Save changes
    context.SaveChanges();
}
它怎么知道 Price 改变了?因为它只是 Book 类上的一个普通的 auto 属性? DetectChanges 方法背后的神奇之处。
在某些特定情况下,DbContext 会调用 DetectChanges 方法。最明显的是在调用 SaveChanges 时。在顶层,它的工作方式是:
  • DbContext 为其加载的每个实体制作快照
  • SaveChanges 被调用时,它会继续调用 DetectChanges,这会很神奇地找出发生了什么变化。
  • DbContext 然后负责将正确的命令发送到数据库。

  • 至此,我们知道了 DetectChanges 的职责。现在重要的部分是知道 DetectChanges 何时被调用(除了我们已经知道的 SaveChanges)。这对于最终回答您的“订单”问题至关重要。来自 Arthur Vickers 的链接文章

    The methods that call DetectChanges:

    • DbSet.Find
    • DbSet.Local
    • DbSet.Remove
    • DbSet.Add
    • DbSet.Attach
    • DbContext.SaveChanges
    • DbContext.GetValidationErrors
    • DbContext.Entry
    • DbChangeTracker.Entries

    让我们检查一下演示“断开连接”场景的代码。
    public Task UpdateBook() 
    {
        Book book = null;
        
        // Just loads the book from this context
        using (var context = new MyContext())
        {
            book = context.Books
                .Single(p => p.ISBN == "123456");       
        }
        
        // Starts a new context where the book is going to be updated
        using (var anotherContext = new MyContext())
        {
            // Changed the price - remember this is not loaded from this context!
            book.Price = 40;
        
            // THIS IS KEY: This will call `DetectChanges`      
            // This entity will be tracked by the context now
            anotherContext.Entry(book).State = EntityState.Modified
            
            // Update will occur normally
            anotherContext.SaveChanges();
        }
    }
    
    当我们进入第二个 DbContext, 时,它​​不知道我们的 book 实体。我们更改价格,然后调用 db.Entry(book).State = EntityState.Modified 。此时,DbContext 将开始跟踪它,并调用 DetectChanges。继续调用 SaveChanges 将按预期工作。
    如果我们反其道而行之,在实际更改价格之前调用 db.Entry(book).State = EntityState.Modified 事情会......仍然有效!
    为什么?好吧,使用 db.Entry(book).State 手动更改实体的状态会将实体添加到上下文中,这意味着它将开始跟踪它的更改。
    因此,即使我们调用 db.Entry(book).State 然后在实体上应用更改也无关紧要,因为最后调用 SaveChanges 将再次触发 DetectChanges ,并且由于之前已经调用过,因此实体已经有了快照.
    您可以自己验证此行为的一种方法是运行上面的代码并为 DbContext 启用日志记录:
    // Calling db.Entry.. produces this log:
    
    DetectChanges starting for 'MyContext'.
    Microsoft.EntityFrameworkCore.ChangeTracking:Debug: DetectChanges completed for 'MyContext'.
    Context 'MyContext' started tracking 'Book' entity.
    
    
    // Calling SaveChanges produces this log:
    
    SaveChanges starting for 'MyContext'
    DetectChanges starting for 'MyContext'.
    DetectChanges completed for 'MyContext'.
    Opening connection to database 'BooksDB'
    Beginning transaction with isolation
    ...
    
    现在一些评论:
    在断开连接的情况下,上面的更新将在表中的 ALL COLUMNS 上发出更新。这可能不是您所期望的。有办法防止这种情况。 Read more hereDetectChanges 在内部做了很多事情,不仅仅是对更改应用合并。它负责处理外键、更新导航属性的引用等,并进行“修复”。
    更多资源可供阅读:(尤其是亚瑟·维克斯(Arthur Vickers)的资源!)
    Secrets of DetectChanges Part 1: What does DetectChanges do?
    Secrets of DetectChanges Part 2: When is DetectChanges called automatically?
    Possible Issue with Change Tracker Caching Entity State EF Core 2.0.2
    Working with Disconnected Entity Graph in Entity Framework Core
    Entity Framework Core TrackGraph For Disconnected Data

    关于c# - EF Core 修改后的实体状态如何表现?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54274166/

    相关文章:

    asp.net-core - VS 2015 中的 Asp.net Core EF

    c# - 不能使用前导 .. 退出顶级目录之上

    c# - 在 KeyUp 事件中检测按键

    c# - 递归-使用递归在 .Net 中获取父文件夹序列

    c# - 通过模型构建器转换添加和删除 GUID 前缀

    .net-core - 阻止 EF Core 使用 Merge to Insert

    c# - Entity Framework 核心 : Access parent from child

    c# - 应该在哪个项目中使用事件溯源实时读取 DDD 中的模型(投影)?

    entity-framework - EF 核心 : Built in Created and Edited timestamps

    c# - EF Core 条件(添加)包含到 IQueryable