Aggiorna riga se esiste ancora la logica di inserimento con Entity Framework

Qualcuno ha suggerimenti sul modo più efficiente per implementare la logica “aggiorna riga se esiste altro inserisci” utilizzando Entity Framework?

Se stai lavorando con un object collegato (object caricato dalla stessa istanza del contesto) puoi semplicemente usare:

if (context.ObjectStateManager.GetObjectStateEntry(myEntity).State == EntityState.Detached) { context.MyEntities.AddObject(myEntity); } // Attached object tracks modifications automatically context.SaveChanges(); 

Se puoi usare qualche conoscenza sulla chiave dell’object puoi usare qualcosa come questo:

 if (myEntity.Id != 0) { context.MyEntities.Attach(myEntity); context.ObjectStateManager.ChangeObjectState(myEntity, EntityState.Modified); } else { context.MyEntities.AddObject(myEntity); } context.SaveChanges(); 

Se non puoi decidere l’esistenza dell’object tramite il suo ID, devi esaminare la query di ricerca:

 var id = myEntity.Id; if (context.MyEntities.Any(e => e.Id == id)) { context.MyEntities.Attach(myEntity); context.ObjectStateManager.ChangeObjectState(myEntity, EntityState.Modified); } else { context.MyEntities.AddObject(myEntity); } context.SaveChanges(); 

A partire da Entity Framework 4.3, esiste un metodo AddOrUpdate nello spazio dei nomi System.Data.Entity.Migrations :

 public static void AddOrUpdate( this IDbSet set, params TEntity[] entities ) where TEntity : class 

che dal doc :

Aggiunge o aggiorna quadro per chiave quando viene chiamato SaveChanges. Equivalente a un’operazione “upsert” dalla terminologia del database. Questo metodo può essere utile quando si semina dati utilizzando Migrazioni.


Per rispondere al commento di @ Smashing1978 , incollerò le parti pertinenti dal collegamento fornito da @Colin

Il lavoro di AddOrUpdate è quello di garantire che non si creino duplicati quando si seminano i dati durante lo sviluppo.

In primo luogo, eseguirà una query nel database in cerca di un record in cui qualsiasi cosa fornita come chiave (primo parametro) corrisponde al valore della colonna mappata (o ai valori) forniti in AddOrUpdate. Quindi questo è un po ‘loosey-goosey per la corrispondenza, ma perfettamente bene per la semina di dati di tempo di progettazione.

Ancora più importante, se viene trovata una corrispondenza, l’aggiornamento aggiornerà tutti e annullerà tutti quelli che non erano presenti in AddOrUpdate.

Detto questo, ho una situazione in cui sto tracciando i dati da un servizio esterno e inserendo o aggiornando i valori esistenti con la chiave primaria (e i miei dati locali per i consumatori sono di sola lettura) – utilizzo AddOrUpdate in produzione da oltre 6 mesi e finora nessun problema

Se sai che stai utilizzando lo stesso contesto e non scollegando alcuna quadro, puoi creare una versione generica come questa:

 public void InsertOrUpdate(T entity, DbContext db) where T : class { if (db.Entry(entity).State == EntityState.Detached) db.Set().Add(entity); // If an immediate save is needed, can be slow though // if iterating through many entities: db.SaveChanges(); } 

db può ovviamente essere un campo di class, o il metodo può essere reso statico e un’estensione, ma questo è il punto di partenza.

La risposta di Ladislav era vicina, ma ho dovuto fare un paio di modifiche per farlo funzionare in EF6 (database-first). Ho esteso il contesto dei miei dati con il mio metodo AddOrUpdate e finora sembra funzionare bene con gli oggetti distaccati:

 using System.Data.Entity; [....] public partial class MyDBEntities { public void AddOrUpdate(MyDBEntities ctx, DbSet set, Object obj, long ID) { if (ID != 0) { set.Attach(obj); ctx.Entry(obj).State = EntityState.Modified; } else { set.Add(obj); } } [....] 

La magia si verifica quando si chiama SaveChanges() e dipende EntityState corrente. Se l’ quadro ha un EntityState.Added , sarà aggiunto al database, se ha un EntityState.Modified , sarà aggiornato nel database. Quindi puoi implementare un metodo InsertOrUpdate() come segue:

 public void InsertOrUpdate(Blog blog) { using (var context = new BloggingContext()) { context.Entry(blog).State = blog.BlogId == 0 ? EntityState.Added : EntityState.Modified; context.SaveChanges(); } } 

Ulteriori informazioni su EntityState

Se non riesci a verificare Id = 0 per determinare se si tratta di una nuova quadro o meno, controlla la risposta di Ladislav Mrnka .

Inserisci altro aggiornamento entrambi

 public void InsertUpdateData() { //Here TestEntities is the class which is given from "Save entity connection setting in web.config" TestEntities context = new TestEntities(); var query = from data in context.Employee orderby data.name select data; foreach (Employee details in query) { if (details.id == 1) { //Assign the new values to name whose id is 1 details.name = "Sanjay"; details. Surname="Desai"; details.address=" Desiwadi"; } else if(query==null) { details.name="Sharad"; details.surname=" Chougale "; details.address=" Gargoti"; } //Save the changes back to database. context.SaveChanges(); } 

Secondo me vale la pena affermare che con il nuovo EntityGraphOperations per Entity Framework Code First puoi risparmiare la scrittura di alcuni codici ripetitivi per definire gli stati di tutte le quadro nel grafico. Sono l’autore di questo prodotto. E l’ho pubblicato nel github , progetto di codice ( include una dimostrazione passo passo e un progetto di esempio è pronto per il download) e nuget .

Imposta automaticamente lo stato delle entity framework su Added o Modified . E sceglierai manualmente quali quadro devono essere cancellate se non esistono più.

L’esempio:

Diciamo che ho ottenuto un object Person . Person potrebbe avere molti telefoni, un documento e potrebbe avere un coniuge.

 public class Person { public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string MiddleName { get; set; } public int Age { get; set; } public int DocumentId {get; set;} public virtual ICollection Phones { get; set; } public virtual Document Document { get; set; } public virtual PersonSpouse PersonSpouse { get; set; } } 

Voglio determinare lo stato di tutte le quadro incluse nel grafico.

 context.InsertOrUpdateGraph(person) .After(entity => { // Delete missing phones. entity.HasCollection(p => p.Phones) .DeleteMissingEntities(); // Delete if spouse is not exist anymore. entity.HasNavigationalProperty(m => m.PersonSpouse) .DeleteIfNull(); }); 

Inoltre, come saprai, le proprietà chiave uniche potrebbero giocare un ruolo durante la definizione dello stato dell’ quadro Telefono. Per tali scopi speciali abbiamo la class ExtendedEntityTypeConfiguration<> , che eredita da EntityTypeConfiguration<> . Se vogliamo utilizzare tali configurazioni speciali, dobbiamo ereditare le nostre classi di mapping da ExtendedEntityTypeConfiguration<> , piuttosto che EntityTypeConfiguration<> . Per esempio:

 public class PhoneMap: ExtendedEntityTypeConfiguration { public PhoneMap() { // Primary Key this.HasKey(m => m.Id); … // Unique keys this.HasUniqueKey(m => new { m.Prefix, m.Digits }); } } 

È tutto.