Sto utilizzando Entity Framework Core per archiviare un oggetto grafico in un database. In momenti diversi mentre sto costruendo il grafico, creo un'entità, la memorizzo nel database e il rilascio il contesto. Tuttavia, sto riscontrando un problema in cui EFC sta tentando di inserire un'entità che è già stata inserita quando è connessa a una nuova entità. Questo è meglio spiegato con il codice. Ecco un breve pezzo di codice (questo è un codice di linea retta, ma i due usi dei contesti si verificano in momenti e luoghi diversi nel codice).
Nella seconda chiamata a context.SaveChanges()
, ottengo la seguente eccezione:
SqlException:
Impossibile inserire il valore esplicito per la colonna Identity nella tabella "Namespace" quando IDENTITY_INSERT è impostato su OFF.
Quando guardo l'SQL che si sta eseguendo, sta provando a inserire di nuovo l'entità dello spazio dei nomi, presumibilmente perché myType viene salvato nel DB e ha un riferimento all'entità dbNamespace
.
// see if namespace is in the db and add it if not
string someNamespaceString = "foobar";
CodeDatabase.Models.Namespace dbNamespace;
using (var context = new CodeFactsContext())
{
dbNamespace = context.Namespace.FirstOrDefault(ns => ns.Namespace1 == someNamespaceString);
if (dbNamespace == null)
{
dbNamespace = new Namespace() { Namespace1 = someNamespaceString };
context.Namespace.Add(dbNamespace);
}
context.SaveChanges();
}
// Type entity created somewhere from the code
var myType = new CodeDatabase.Models.Type()
{
FullName = "foobar.mytype",
ShortName = "mytype",
Namespace = dbNamespace // this is already in the DB
};
// check if myType is in the db and add it if not
using (var context = new CodeFactsContext())
{
var dbType = context.Type.FirstOrDefault(t => t.FullName == myType.FullName);
if (dbType == null)
{
dbType = myType;
context.Add(dbType);
}
context.SaveChanges(); // throws exception
}
Qualche idea su come ottenere EF Core per riconoscere (nel secondo context.SaveChanges()
) che myType
dovrebbe essere inserito nel database, ma myType.Namespace
non dovrebbe perché è già lì? Entrambe le entità hanno un ID int che viene generato automaticamente dal DB e l'id di Namespace è impostato sul valore del database dopo la prima chiamata a SaveChanges
. Pensavo che l'EF Core avrebbe riconosciuto che l'id non era 0 e non provava a salvarlo. Qualsiasi aiuto / suggerimento molto gradito.
Pensavo che EFC avrebbe riconosciuto che l'ID non era 0 e non provava a salvarlo.
Il problema è che si sta utilizzando il metodo Add
che contrassegna tutte le entità raggiungibili e non tracciate come nuove, indipendentemente dal valore della chiave (per consentire l'inserimento di identità negli scenari). Questo è spiegato nelle Entità disconnesse - Lavorare con i grafici - Tutte le nuove / tutte le entità esistenti . Mentre il tuo screnario cade in Mix di entità nuove ed esistenti .
Qualsiasi idea di come raggiungere EFC a riconoscere (nel secondo
context.SaveChanges
) chemyType
deve essere inserito nel database, mamyType.Namespace
non dovrebbe perché è già lì? Entrambe le entità hanno un IDint
che viene generato automaticamente dal DB e l'id di Namespace è impostato sul valore del database dopo la prima chiamata aSaveChanges
.
In realtà c'è una soluzione semplice spiegata nel secondo link alla documentazione:
Con le chiavi generate automaticamente, l'aggiornamento può essere nuovamente utilizzato per inserti e aggiornamenti, anche se il grafico contiene una combinazione di entità che richiedono l'inserimento e quelle che richiedono l'aggiornamento
dove "again" si riferisce a Saving single entities :
Il metodo di aggiornamento normalmente contrassegna l'entità per l'aggiornamento, non per l'inserimento. Tuttavia, se l'entità ha una chiave generata automaticamente e non è stato impostato alcun valore chiave, l'entità viene invece automaticamente contrassegnata per l'inserimento.
Fortunatamente le tue entità usano le chiavi generate automaticamente, quindi usa semplicemente Update
invece di Add
:
if (dbType == null)
{
dbType = myType;
context.Update(dbType); // <--
}