我们把实体 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 here
DetectChanges
在内部做了很多事情,不仅仅是对更改应用合并。它负责处理外键、更新导航属性的引用等,并进行“修复”。更多资源可供阅读:(尤其是亚瑟·维克斯(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/