Sto cercando di impostare l'ID manualmente per alcune voci.
Ho una classe cliente con un campo Identità
modelBuilder.Entity<Customer>().Property(f => f.Id).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity);
e nella parte di inserto che ho
using (var transaction = ctx.Database.BeginTransaction())
{
ctx.Database.ExecuteSqlCommand("SET IDENTITY_INSERT [dbo].[Customers] ON");
ctx.Customers.AddRange(customersList);
ctx.SaveChanges();
ctx.Database.ExecuteSqlCommand("SET IDENTITY_INSERT [dbo].[Customers] OFF");
transaction.Commit();
}
ma sto ancora ricevendo l'eccezione
Il valore esplicito deve essere specificato per la colonna Identity nella tabella "Customers" quando IDENTITY_INSERT è impostato su ON o quando un utente di replica si sta inserendo in una colonna di identità NOT FOR REPLICATION.
Nella StateEntries della mia eccezione, posso vedere che tutti i campi che sono memorizzati in un'altra tabella come "Contatti" sembra essere la causa customer.Contacts = new List<Contact> {new Contact {Name = "Test", … }}
Come posso farlo funzionare?
Quel messaggio di errore è fuorviante. Stai riuscendo a attivare IDENTITY_INSERT, ma EF sta ancora generando un'istruzione INSERT in base al presupposto che il valore della chiave verrà generato dalla colonna IDENTITY.
Quindi devi anche generare una dichiarazione INSERT contenente il valore della chiave. Ovviamente è possibile utilizzare .ExecuteSqlCommand () per eseguire anche INSERT. Oppure puoi ottenere EF per farlo, ma devi usare un modello in cui quell'entità non ha le chiavi generate dal database. OnModelCreating configura il modello solo una volta per ModelType, quindi non puoi semplicemente inserire un interruttore.
Invece puoi creare un sottotipo del tuo DbContext per il seeding, sovrascrivendo la configurazione dell'entità della base DbContext. Come questo:
class Db_Seed: Db
{
public Db_Seed(string constr) : base(constr)
{
Database.SetInitializer<Db_Seed>(null); //no initializer
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Customer>().Property(c => c.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
}
}
È ancora necessario impostare IDENTITY_INSERT su (poiché la tabella ha IDENTITY), ma con questo contesto EF non genererà un'istruzione INSERT che presuppone che il server genererà la chiave.