如何在EF Core中放棄對上下文的更改

.net c# entity-framework entity-framework-core

我有一個巨大的json格式的“扁平”對象列表,以及一個有點複雜的關係數據庫模式(大約有20個表對應於展平對象)。我正在嘗試在新的關係數據庫中自動插入那些展平的對象:

foreach (var flattenedObject in flattenedObjects)
{
    _repository.Insert(flattenedObject).Wait();
    //some time logging, etc
}

Insert()方法為不同表中的許多相關對象調用AddRangeAsync()AddAsync()

由於扁平化對像是遺留的,我會說它們中有大約0.001%是格式錯誤並且會違反數據庫約束 - 例如嘗試在其中一個表中插入重複的複合主鍵。

我期待這些罕見的錯誤,因此我的想法是 - 將整個Insert()操作包裝在一個事務中 - 如果任何一個操作無效,只是不插入任何東西並記錄錯誤,所以我可以手動修改flattened對象再試一次之前。因此我的代碼看起來有點類似於:

public async Task Insert(FlattenedObject fo)
{
    using (var transaction = _context.Database.BeginTransaction())
    {
        try
        {
            //magical code that calls AddAsync for multiple tables
        }
        catch (Exception ex)
        {
            transaction.Rollback()
            //logging
        }
    }
}

但是,如果在我的try塊中的某處發生錯誤(我嘗試插入違反複合主鍵的對象),則整個上下文對像都會損壞。

導致異常的對象仍然保留在我的DbContext中,隨後在另一個事務中對AddAsync()任何調用AddAsync()觸發新的異常。

我嘗試為上面的foreach循環中的每個新對象重新創建我的DbContext和repo - 但即便如此,如果我查詢:

_context.ChangeTracker.Entries().Where(e => e.State != EntityState.Unchanged);

我看到我的舊對象仍然在dbContext的新實例中。

是否有任何(優雅)方式告訴我的上下文重置所有掛起的更改 - 這樣我可以在發生錯誤時將它放在catch塊中?我希望在失敗的交易中發生的一切都留在那里而不是洩漏。

一般承認的答案

下面的代碼對我有用。但是,如果有人發布了一個更清潔的解決方案(我仍然希望有一些開箱即用的EF),我會接受它。

private void ResetContextState() => _context.ChangeTracker.Entries()
    .Where(e => e.Entity != null).ToList()
    .ForEach(e => e.State = EntityState.Detached);


Related

許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow