簡體   English   中英

實體框架Core1.1-批量插入或更新-InvalidOperationException

[英]Entity Framework Core1.1 - Bulk Insert or Update - InvalidOperationException

我在插入或更新大約950個實體時遇到問題。

var coins = JsonConvert.DeserializeObject<List<Currency>>(json);
var sw = new Stopwatch();
sw.Start();
using (var ctx = CryptoContext.Get)
{
    var existingCoins = ctx.Coins.ToList();
    foreach (var coin in coins)
    {
        var existing = existingCoins.FirstOrDefault(c => c.CMC_Id == coin.CMC_Id);
        if (existing != null)
        {
            ctx.Entry<Currency>(coin).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
        } else
        {
            ctx.Entry<Currency>(coin).State = Microsoft.EntityFrameworkCore.EntityState.Added;
        }

    }
    ctx.SaveChanges();
    var el = sw.ElapsedMilliseconds;
}

該代碼使用SQLite在netcoreapp1.1的后台運行,並檢索貨幣列表。 使用FluentScheduler每5分鍾完成一次。 因為它們不是完全大的對象,所以我會在內存中進行所有比較,並嘗試添加或更新每個對象。 我的實體具有數據庫給定的ID,並且我要從中獲取的API保證CMC_Id是唯一的。

初始插入工作正常。 我在第二個“更新”時遇到錯誤。 我相信發生的事情是我正在跟蹤多個實體,每個實體的ID為0

我正在嘗試遵循此方法: https : //msdn.microsoft.com/zh-cn/library/jj592676(v=vs.113).aspx

我得到的錯誤是: "The instance of entity type 'Currency' cannot be tracked because another instance of this type with the same key is already being tracked. When adding new entities, for most key types a unique temporary key value will be created if no key is set (ie if the key property is assigned the default value for its type). If you are explicitly setting key values for new entities, ensure they do not collide with existing entities or temporary values generated for other new entities. When attaching existing entities, ensure that only one entity instance with a given key value is attached to the context."

我不確定如何繼續更新每一行。

此處發出要求跟蹤具有相同密鑰的多個實體。

當您將EntityEntry.State設置為某種值時,EF Core將開始跟蹤處於特定狀態的實體。 由於在您的代碼中,您正在查詢數據庫以查找現有實體,因此EF Core將開始使用給定的密鑰跟蹤該實體,因此在設置EntityEntry.State時會拋出異常,因為已經存在具有相同密鑰的實體。

更准確地說,您正在嘗試AddOrUpdate 有多種方法可以實現該行為。 哪一個最佳取決於您要添加一個沒有關系或復雜圖的實體。

最簡單的方法是僅檢查存在性,而不是從數據庫中跟蹤實體。 可以選擇在查詢中使用AsNoTracking ,以便EF不會開始對其進行跟蹤。 甚至更優化的方法是僅從數據庫中獲取計數。 如果要查詢PK屬性,則計數將為0(不存在)或1(現有實體)。 如果不存在,則調用Add否則調用Update

var updatedBlog = new Blog { Id = 1, Title = "Updated" };
var exist = db.Blogs.Count(b => b.Id == updatedBlog.Id) != 0;
if (exist)
{
    db.Update(updatedBlog);
}
else
{
    db.Add(updatedBlog);
}
db.SaveChanges();

由於“ Add或“ Update方法開始跟蹤整個圖形,因此,如果您的圖形處於一種一致的狀態(所有實體都是新實體,或者所有實體都正在被修改),那么它就可以正常工作。

如果您的圖形有些不一致,則圖形中每個節點的狀態可能會有所不同(例如,更新博客但其中有新帖子)。 然后,您應該在單個實體上使用EntityEntry.State 這樣可以確保狀態僅應用於給定的實體,而不會應用於圖中的其他相關實體。 盡管您需要對圖形中的每個節點進行上述檢查。 另一種選擇是使用Attach方法將整個圖AttachUnchanged狀態,然后為單個節點設置狀態。

如果您具有自動生成的鍵值,則可能只有在更新時才設置PK值,否則它將是CLR默認值。 對於沒有關系的單個實體,您可以自己檢查而不是像上面的代碼那樣查詢數據庫並做出決定。 對於圖形,您可以使用

db.ChangeTracker.TrackGraph(updatedBlog, n => n.Entry.State = n.Entry.IsKeySet ? EntityState.Modified : EntityState.Added);

這將根據是否設置PK值來設置每個節點的狀態。

希望這可以幫助 :)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM