Molte e molte relazioni non salvano

Ho due quadro con una relazione da molti a molti abbastanza standard che ho creato in EF 5 Code First. Questi sono Service e ServiceItem. L’ quadro Servizio contiene una raccolta di ServiceItem e ServiceItem contiene una raccolta di Servizi. Posso creare, modificare e salvare dati in una delle proprietà di base delle entity framework senza problemi. Quando provo ad aggiungere un ServiceItem a un servizio o un servizio a un ServiceItem, sembra funzionare, ma non viene salvato nulla. Ho verificato che tutte le tabelle del database corrette vengano create, inclusa una tabella ServiceItemService con le chiavi incrociate. La tabella ServiceItemService del database non riceve alcuna voce quando aggiungo gli elementi. Non c’è errore e tutto il resto sembra funzionare perfettamente.

Sono un po ‘perplesso e potrei usare un po’ di aiuto. Di seguito sono elencate le classi.

La class di servizio;

public class Service { //Default constructor public Service() { //Defaults IsActive = true; ServicePeriod = ServicePeriodType.Monthly; ServicePeriodDays = 0; ServiceItems = new Collection(); } public int ServiceID { get; set; } public string Title { get; set; } public string Description { get; set; } public ICollection ServiceItems { get; set; } public string TermsOfService { get; set; } public ServicePeriodType ServicePeriod { get; set; } public int ServicePeriodDays { get; set; } public bool IsActive { get; set; } } 

La class ServiceItem;

 public class ServiceItem { public ServiceItem() { IsActive = true; } public int ServiceItemID { get; set; } public string Title { get; set; } public string Description { get; set; } public ICollection Services { get; set; } public string UserRole { get; set; } public bool IsActive { get; set; } } 

Questa è la mapping Fluent che ho fatto durante il tentativo di eseguire il debug di questo problema. Lo stesso problema si è verificato prima e dopo l’aggiunta di questa mapping.

  public DbSet Services { get; set; } public DbSet ServiceItems { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity() .HasMany(p => p.ServiceItems) .WithMany(r => r.Services) .Map(mc => { mc.MapLeftKey("ServiceItemID"); mc.MapRightKey("ServiceID"); mc.ToTable("ServiceItemService"); }); } 

Ecco il codice che uso per salvare l’elemento Servizio che include 2-3 ServiceItems nella raccolta Service.ServiceItems. Ho verificato con attenzione che i ServiceItem erano nella corretta collezione.

  db.Entry(dbService).State = EntityState.Modified; db.SaveChanges(); 

L’object dbService non sembra essere influenzato in alcun modo. I ServiceItem sono ancora nella raccolta corretta, ma non vengono apportati aggiornamenti alla tabella del database ServiceItemService. Qualsiasi consiglio sarebbe molto gradito.

-Grazie

È previsto che non accada nulla.

Ciò che si desidera modificare o aggiungere è una relazione tra le quadro Service e ServiceItem . Ma non puoi manipolare le relazioni impostando lo stato di un’entity framework su Modified . Questo aggiorna solo le proprietà scalari e complesse ma nessuna proprietà di navigazione (= relazioni). Ad esempio, l’impostazione dello stato di un’ quadro Service su Modified segnerà Service.Title e Service.Description , ecc. Come modificato e assicurerà che tali proprietà vengano salvate nel database, ma non si preoccupa del contenuto di Service.ServiceItems .)

L’unica eccezione in cui è ansible modificare una relazione impostando lo stato su Modified sono le associazioni di chiavi esterne . Si tratta di associazioni che hanno proprietà di chiavi esterne esposte nell’ quadro del modello e possono verificarsi solo per le associazioni uno-a-molti o one-to-one. Le relazioni many-to-many sono sempre associazioni indipendenti, il che significa che non possono mai avere una proprietà di chiave esterna in un’entity framework. (Poiché gli FK si trovano nella tabella di join, ma la tabella di join non è un’ quadro e “nascosta” dalle classi del modello.)

Esiste un modo per manipolare direttamente le relazioni per un’associazione many-to-many ma è necessario scendere ObjectContext e al suo RelationshipManager che, a mio avviso, è piuttosto avanzato e complicato.

Il modo usuale e diretto per aggiungere e rimuovere voci di relazione da / a un’associazione molti-a-molti è semplicemente aggiungendo elementi e rimuovendo elementi dalle raccolte mentre le quadro sono collegate al contesto. Il meccanismo di rilevamento delle modifiche di EF riconoscerà le modifiche apportate e genererà le istruzioni INSERT, UPDATE e DELETE appropriate quando chiami SaveChanges .

La procedura esatta dipende se si desidera salvare Service e / o ServiceItem come nuove entity framework o se si desidera solo aggiungere relazioni tra entity framework esistenti. Ecco alcuni esempi:

  • service dovrebbe essere INSERITO, tutti i serviceItem dovrebbero essere INSERITI e le relazioni tra le quadro dovrebbero essere INSERITE anche nella tabella di join:

     using (var context = new MyContext()) { var service = new Service(); var serviceItem1 = new ServiceItem(); var serviceItem2 = new ServiceItem(); service.ServiceItems.Add(serviceItem1); service.ServiceItems.Add(serviceItem2); context.Services.Add(service); context.SaveChanges(); } 

    L’aggiunta del servizio “root” del grafico dell’object è sufficiente perché EF riconoscerà che tutte le altre quadro nel grafico non sono collegate al contesto e presuppongono che debbano essere INSERITE nel database.

  • service esiste già e NON dovrebbe essere INSERTO, tutti i serviceItem dovrebbero essere INSERITI e le relazioni tra le quadro dovrebbero essere INSERITE anche nella tabella di join:

     using (var context = new MyContext()) { var service = new Service { ServiceID = 15 }; context.Services.Attach(service); var serviceItem1 = new ServiceItem(); var serviceItem2 = new ServiceItem(); service.ServiceItems.Add(serviceItem1); service.ServiceItems.Add(serviceItem2); context.SaveChanges(); } 

    EF riconosce qui (quando si chiama SaveChanges ) quel service è collegato ma le altre quadro no. Nessun INSERT per il service ma serviceItem1/2 sarà INSERITO insieme alle voci della relazione.

  • service esiste già e NON dovrebbe essere INSERITO, tutti i serviceItem esistono già e NON dovrebbero essere INSERITI, ma le relazioni tra le entity framework dovrebbero essere INSERITE nella tabella di join:

     using (var context = new MyContext()) { var service = new Service { ServiceID = 15 }; context.Services.Attach(service); var serviceItem1 = new ServiceItem { ServiceItemID = 23 }; context.ServiceItems.Attach(serviceItem1); var serviceItem2 = new ServiceItem { ServiceItemID = 37 }; context.ServiceItems.Attach(serviceItem2); service.ServiceItems.Add(serviceItem1); service.ServiceItems.Add(serviceItem2); context.SaveChanges(); } 
  • Per completezza: come rimuovere le relazioni tra quadro esistenti?

     using (var context = new MyContext()) { var service = context.Services .Include(s => s.ServiceItems) // load the existing Items .Single(s => s.ServiceID == 15); var serviceItem1 = service.ServiceItems .Single(s => s.ServiceItemID == 23); // query in memory, no DB query var serviceItem2 = service.ServiceItems .Single(s => s.ServiceItemID == 37); // query in memory, no DB query service.ServiceItems.Remove(serviceItem1); service.ServiceItems.Remove(serviceItem2); context.SaveChanges(); } 

    Le due righe di relazione nella tabella join che collegano il servizio 15 con serviceItem 23 e 37 verranno eliminate.

Alternativamente invece di chiamare Attach puoi caricare le quadro esistenti dal database. Funzionerà pure:

 var service = context.Services.Single(s => s.ServiceID == 15); 

E lo stesso per i ServiceItem esistenti.