6

Ich versuche, eine Customer in meiner Datenbank mit ASP.NET Web API und Entity Framework 5 Code zuerst zu aktualisieren, aber es ist nicht Arbeiten. Meine Entitäten sehen so aus:EF5-Code zuerst mit ASP.NET-Web-API: Update-Entität mit Viele-zu-viele-Beziehung

public class CustomerModel 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 

    // More fields 

    public ICollection<CustomerTypeModel> CustomerTypes { get; set; } 
} 

public class CustomerTypeModel 
{ 
    public int Id { get; set; } 
    public string Type { get; set; } 

    [JsonIgnore] 
    public ICollection<CustomerModel> Customers { get; set; } 
} 

Nichts ist so besonders. Ich habe eine Webschnittstelle aufgebaut, über die Benutzer einen Kunden hinzufügen können, indem sie den Namen angeben und einen oder mehrere Kundentypen prüfen. Wenn die Schaltfläche zum Senden schlagen, werden die Daten auf meiner Web-API-Methode gesendet:

public void Put([FromBody]CustomerModel customer) 
{ 
    using (var context = new MyContext()) 
    { 
     context.Customers.Attach(customer); 
     context.Entry(customer).State = EntityState.Modified; 
     context.SaveChanges(); 
    } 
} 

Damit werden die Kundenfelder aktualisiert, sondern die damit verbundenen Kundentypen ignoriert werden. Das eingehende customer Objekt hat eine Liste von CustomerTypes enthalten sollte es mit in Verbindung gebracht werden:

[0] => { Id: 1, Type: "Finance", Customers: Null }, 
[1] => { Id: 2, Type: "Insurance", Customers: Null } 
[2] => { Id: 3, Type: "Electronics", Customers: Null } 

Doch statt in dieser Liste suchen und das Hinzufügen/Entfernen von assoziierten Unternehmen, EF ignoriert es einfach. Neue Assoziationen werden ignoriert und bestehende Assoziationen bleiben bestehen, selbst wenn sie gelöscht werden sollten.

Ich hatte ein ähnliches Problem beim Einfügen eines Kunden in die Datenbank, das wurde behoben, wenn ich den Zustand dieser Entitäten auf EntityState.Unchanged eingestellt. Natürlich habe ich versucht, in meinem Update-Szenario denselben magischen Fix anzuwenden:

Aber EF zeigt das gleiche Verhalten an.

Irgendwelche Ideen, wie Sie das beheben können? Oder sollte ich wirklich nur eine manuelle Löschung der Liste von CustomerTypes machen und sie dann manuell hinzufügen?

Vielen Dank im Voraus.

JP

Antwort

10

Dies ist nicht wirklich lösbar nur durch Einheit Staaten zu setzen. Sie müssen den Kunden zuerst aus der Datenbank laden, einschließlich aller seiner aktuellen Typen, und dann die Typen aus dem geladenen Kunden entfernen oder Typen hinzufügen, entsprechend der aktualisierten Typsammlung des gebuchten Kunden. Änderungsverfolgung wird den Rest erledigen Einträge aus der Tabelle verbinden, zu löschen oder einzufügen neue Einträge:

public void Put([FromBody]CustomerModel customer) 
{ 
    using (var context = new MyContext()) 
    { 
     var customerInDb = context.Customers.Include(c => c.CustomerTypes) 
      .Single(c => c.Id == customer.Id); 

     // Updates the Name property 
     context.Entry(customerInDb).CurrentValues.SetValues(customer); 

     // Remove types 
     foreach (var typeInDb in customerInDb.CustomerTypes.ToList()) 
      if (!customer.CustomerTypes.Any(t => t.Id == typeInDb.Id)) 
       customerInDb.CustomerTypes.Remove(typeInDb); 

     // Add new types 
     foreach (var type in customer.CustomerTypes) 
      if (!customerInDb.CustomerTypes.Any(t => t.Id == type.Id)) 
      { 
       context.CustomerTypes.Attach(type); 
       customerInDb.CustomerTypes.Add(type); 
      } 

     context.SaveChanges(); 
    } 
} 
+0

Yep, fürchtete ich diese Anleitung Art und Weise, Dinge zu tun. Danke für den Code, arbeitete wie ein Charme und rettete mir einige Schwierigkeiten mit Staaten zu kämpfen :) –

+0

Gibt es eine Möglichkeit, diese generische, so dass es für jede Navigationseigenschaft funktioniert? – CodyK

+0

@Codemiester: Sie können einen Blick auf die GraphDiff-Bibliothek werfen, die in den Kommentaren hier erwähnt wird: http://entityframework.codeplex.com/workitem/864 – Slauma

0

Eine sauberere Lösung wäre:

public void Put([FromBody]CustomerModel customer) 
{ 
    using (var context = new MyContext()) 
    { 
     var customerInDb = context.Customers.Include(c => c.CustomerTypes) 
      .Single(c => c.Id == customer.Id); 

     // Updates the Name property 
     context.Entry(customerInDb).CurrentValues.SetValues(customer); 

     // Remove types 
     customer.CustomerTypes.Clear(); 

     // Add new types 
     foreach (var type in customer.CustomerTypes) 
     { 
      context.CustomerTypes.Attach(type); 
      customerInDb.CustomerTypes.Add(type); 
     } 

     context.SaveChanges(); 
    } 
} 
+0

Gibt es eine Möglichkeit, dies generisch zu machen, damit es für jede Navigationseigenschaft funktioniert? – CodyK

Verwandte Themen