Le mie entità sono:
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; }
...
}
Il metodo add è:
public async Task AddAsync(TEntity entity)
{
await Task.Factory.StartNew(() => this.entities.Add(entity));
}
L'entità che sto aggiungendo è:
ShoppingCartItem()
{
CustomerId = "xxxxx",
ProductId = 1,
Customer = null,
Product = null
}
Quando chiamo SaveChanges () l'EF sta cercando di inserire due record identici per ShoppingCartItem
. ShoppingCartItem
viene creato e aggiunto al contesto solo una volta. Qualche idea su cosa potrebbe essere sbagliato?
MODIFICARE:
Ecco come chiamo il metodo AddSync:
public async Task AddNewCartItem(ShoppingCartItem shopingCartItem)
{
await this.ShoppingCartItemRepository.AddAsync(shopingCartItem);
await this.SmartStoreWorkData.CompleteAsync();
}
AGGIORNAMENTO: ho fatto quanto segue:
comandi:
dotnet ef --startup-project ../SmartStoreNetCore.Web/ migrations add ChangeShoppingCartItemKey
dotnet ef --startup-project ../SmartStoreNetCore.Web/ database update
Rimosso il seguente tag duplicato in _Layout.cshtml
<script src="~/js/site.js" asp-append-version="true"></script>
site.js
contiene il gestore di eventi click per la funzionalità Aggiungi al carrello
Posso confermare completamente che il seguente metodo è stato chiamato due volte prima di rimuovere il riferimento duplicato a
site.js
:
public async Task AddNewCartItem(ShoppingCartItem shopingCartItem)
{
await this.ShoppingCartItemRepository.AddAsync(shopingCartItem);
await this.SmartStoreWorkData.CompleteAsync();
}
È un mistero per me perché non l'hai capito prima tramite il debugging
La tua configurazione dovrebbe essere simile a:
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);
Avere un valore generato automaticamente non lo definisce come chiave primaria
DbContext
non è thread-safe . Con - inutilmente, come notato nei commenti - eseguendo il tuo .Add()
in quello che è molto probabilmente un thread diverso, stai confondendo il DbContext
. Add()
è puramente un'operazione in memoria; non c'è motivo di provare a renderlo asincrono. Cambialo e penso che risolverà il problema.
public void Add(TEntity entity)
{
this.entities.Add(entity);
}
Se hai altri usi simili che non sono mostrati nella tua domanda, cambia anche quelli da sincronizzare.
È possibile eseguire "corretto" asincrono con DbContext
ma è solo per i metodi che effettivamente comunicano con il database, non con quelli in memoria, e di solito non implicano Task.<anything>
, solo i metodi async
forniti.
Modifica : per completezza, il link sopra è per EF6, ma in EF Core, DbContext
non è thread-safe .