![](/img/trans.png)
[英]Breeze SaveChanges always throws DbUpdateConcurrencyException when deleting entity
[英]Does Entity Framework Core DbContext SaveChanges call DetectChanges implicitly when it throws DbUpdateConcurrencyException?
作為一個場景,一個實體有一個 xmin 並發檢查,它相當於 PostgreSQL 數據庫中的RowVersion
列。 在更新這個實體時,有一個類似下面的循環來強制更新操作作為獲勝策略的最后一個。
var entities = entityListContainsEntitiesModifiedByUser;
using var context = new ExampleDbContext();
while(true)
{
try
{
var entitiesWillBeUpdated = context.Set<TEntity>().Where(x => !entities.Contains(x)).ToList();
context.UpdateRange(entitiesWillBeUpdated);
// Some of entities have deleted since round before.
// (This line will be mentioned later below)
context.ChangeTracker.DetectChanges();
var revertEntities = context.ChangeTracker.Entries<TEntity>().Where(x => !entitiesWillBeUpdated.Contains(x.Entity)).ToList();
foreach(var revert in reverEntities)
{
revert.State == EntityState.Detach;
}
context.SaveChanges();
break;
}
catch(DbUpdateConcurrencyException e)
{
var entry = e.Entries.Single();
var dbval = await entry.GetDatabaseValues();
if (dbval == null)
{
// Updating entry has been deleted so it cant be modified. Ignore it.
entry.State = EntityState.Detached;
continue;
}
// Updating entry has been concurrently updated by someone else so change the old version to the new one
var pxmin = entry.Property("xmin")!;
pxmin.CurrentValue = dbval.GetValue<uint>("xmin");
pxmin.OriginalValue = dbval.GetValue<uint>("xmin");
}
}
如果我們一步一步來,假設用戶修改了 1000 個實體,我們想要更新這些。 在嘗試塊中,所有 1000 個實體都被跟蹤並設置為已修改。 此時有 0 個 revertEntities,因為這是第一輪,因此之前沒有從數據庫中獲取跟蹤實體。 然后,調用SaveChanges
。 在 EF Core 更新這些實體時,其他用戶同時在這 1000 個實體中修改了 1 個實體。
因此捕獲了DbUpdateConcurrencyException
。 在 catch 塊中設置了這個 1 實體的新 xmin 版本。 在再次嘗試更新所有 1000 條記錄之前,有一段時間,假設在這段時間內,1000 條記錄中的 300 條記錄被刪除。 在下一輪,entitiesWillBeUpdated 有 700 條記錄, ExampleDbContect
跟蹤前一輪加載的 1000 個實體,其中 300 個從數據庫中刪除,因此 revertEntities 里面有 300 個實體。
這 300 個實體被設置為分離並調用SaveChanges
。
此時,另一個用戶再次修改了 700 個實體中的 1 個。 在下一輪中,這 1 個修改實體的 xmin 版本被更新。
問題是:
此時, revertEntities
是否會再次具有 300 個分離的實體,或者它們是否從ExampleDbContext
中清除並且由於之前進行了一輪SaveChanges
調用而未被跟蹤,所以它內部是否會有 0 個實體?
我知道 SaveChanges 隱式調用context.ChangeTracker.DetectChanges()
但如果拋出DbUpdateConcurrencyException
怎么辦?
我知道,當拋出此異常時,內存中的狀態設置為已修改的跟蹤實體值不會更改,但如果沒有異常,則此實體值具有與更新的數據庫中的記錄相同的新值。 對於分離的實體也是如此嗎?
通常,如果沒有引發錯誤,所有這些都將從ExampleDbContext
中清除並且不會被跟蹤。 那么在最后一種情況下,分離的實體是否被清除或它們仍然存在於本地? 我需要像代碼中的注釋行一樣手動調用DetectChanges()
嗎?
我在另一個項目中測試了這個案例,我看到,在分離跟蹤條目並啟用 AutoDetectChanges(默認情況下啟用)時,條目會在Entry.State = EntryState.Detached
行之后立即從 ChangeTracker 的條目列表中刪除。 因此,無需等待 SaveChanges 或 DetectChanges 調用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.