Entity Framework Core嘗試在調用SaveChanges()時插入重複的記錄

c# entity-framework entity-framework-core

我的實體是:

public class Customer
{
   ...
   public virtual ICollection<ShoppingCartItem> ShoppingCartItems { get; set; }
   ...
}

public class ShoppingCartItem
{
   public string CustomerId { get; set; }
   public int ProductId { get; set; }
   public virtual Customer { get; set; }
   public virtual Product{ get; set; }
   ...
}

add方法是:

public async Task AddAsync(TEntity entity)
{
    await Task.Factory.StartNew(() => this.entities.Add(entity));
}

我要添加的實體是:

ShoppingCartItem()
{
    CustomerId = "xxxxx",
    ProductId = 1,
    Customer = null,
    Product = null 
}

當我調用SaveChanges()時,EF正在嘗試為ShoppingCartItem插入兩個相同的記錄。 ShoppingCartItem只創建一次並添加到上下文中。什麼可能是錯的想法?

編輯:

這就是我調用AddSync方法的方法:

public async Task AddNewCartItem(ShoppingCartItem shopingCartItem)
    {
        await this.ShoppingCartItemRepository.AddAsync(shopingCartItem);
        await this.SmartStoreWorkData.CompleteAsync();
    }

一般承認的答案

更新:我做了以下事情:

  • 克隆您的repo鏈接: SmartStoreNETCore
  • 使用新的EF工具遷移到.NET Core 1.1(preview4)
  • 添加了下面的EF ModelBuilder中指定的配置
  • 應用遷移和更新的數據庫

命令:

dotnet ef --startup-project ../SmartStoreNetCore.Web/ migrations add ChangeShoppingCartItemKey
dotnet ef --startup-project ../SmartStoreNetCore.Web/ database update
  • 刪除了_Layout.cshtml的以下重複標記

    <script src="~/js/site.js" asp-append-version="true"></script>

site.js包含“ 添加到購物車”功能的單擊事件處理程序

  • 啟動網站, 一切按預期工作,沒有重複的購物車項目,數量按預期更新

在此處輸入圖像描述

綜上所述

我可以完全確認在刪除對site.js的重複引用之前,已調用以下方法兩次

 public async Task AddNewCartItem(ShoppingCartItem shopingCartItem)
 {
     await this.ShoppingCartItemRepository.AddAsync(shopingCartItem);
     await this.SmartStoreWorkData.CompleteAsync();
 }

對我來說,為什麼在調試前沒有發現這個問題,這是一種謎

EF ModelBuilder

您的配置應如下所示:

builder.Entity<ShoppingCartItem>().HasKey(x => x.Id); // Notice this!
builder.Entity<ShoppingCartItem>().Property(x => x.Id).ValueGeneratedOnAdd(); // Also this!
builder.Entity<ShoppingCartItem>().HasOne(s => s.Customer).WithMany(b => b.ShoppingCartItems).OnDelete(DeleteBehavior.Restrict);
builder.Entity<ShoppingCartItem>().HasOne(s => s.Product).WithMany().OnDelete(DeleteBehavior.Restrict);

擁有自動生成的值不會將其定義為主鍵


熱門答案

DbContext 不是線程安全的 。毫無意義地,如評論中所述 - 在非常可能是不同的線程中執行.Add() ,你會混淆DbContextAdd()純粹是一個內存中的操作;沒有理由試圖讓它異步。改變這一點,我認為它將解決問題。

public void Add(TEntity entity)
{
    this.entities.Add(entity);
}

如果您有任何其他類似的用法未在您的問題中顯示,請將其更改為同步。

可以使用DbContext執行“正確”異步,但它僅適用於實際與數據庫通信的方法,而不是內存中的方法,並且通常不會涉及Task.<anything> ,只提供async方法。

編輯 :為完整DbContext ,上面的鏈接適用於DbContext ,但在EF Core中, DbContext線程安全的



Related

許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因