2012-11-15 17 views
8

Angenommen, ich habe folgende Modellklassen in einem Entity Framework-Code-First-Setup:Aktualisierung getrennt Einheiten mit many-to-many-Beziehungen

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

    public virtual ICollection<Team> Teams { get; set; } 
} 

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

    public virtual ICollection<Person> People { get; set; } 
} 

Die Datenbank von diesem Code erstellt wird, umfasst eine TeamPersons Tabelle, die die viele zu viele Beziehungen zwischen Menschen und Teams.

Angenommen, ich habe ein getrenntes Person-Objekt (kein Proxy und noch keinem Kontext zugeordnet), dessen Team-Sammlung ein oder mehrere getrennte Team-Objekte enthält, die alle Teams repräsentieren, die sich bereits in der Datenbank befinden. Ein Objekt wie durch die folgende geschaffen würde, nur zum Beispiel, wenn eine Person mit der ID 1 und ein Team mit Id 3 bereits in der db bestanden:

var person = new Person 
{ 
    Id = 1, 
    Name = "Bob", 
    Teams = new HashSet<Team> 
    { 
     new Team { Id = 3, Name = "C Team"} 
    } 
}; 

Was ist der beste Weg, um diese Aufgabe zu aktualisieren, Damit nach dem Update die TeamPersons-Tabelle eine einzelne Zeile für Bob enthält, die ihn mit C Team verbindet? Ich habe die offensichtlich versucht:

using (var context = new TestContext()) 
{ 
    context.Entry(person).State = EntityState.Modified; 
    context.SaveChanges(); 
} 

aber die Teams Sammlung wird nur durch diese ignoriert. Ich habe auch verschiedene andere Dinge ausprobiert, aber nichts scheint genau das zu tun, wonach ich hier bin. Danke für jede Hilfe.

EDIT:

So bekomme ich, dass ich sowohl die Person und das Team holen konnte [s] aus der db, aktualisieren sie und dann Änderungen zu übernehmen:

using (var context = new TestContext()) 
{ 
    var dbPerson = context.People.Find(person.Id); 
    dbPerson.Name = person.Name; 
    dbPerson.Teams.Clear(); 
    foreach (var id in person.Teams.Select(x => x.Id)) 
    { 
     var team = context.Teams.Find(id); 
     dbPerson.Teams.Add(team); 
    } 

    context.SaveChanges(); 
} 

Dies ist ein Schmerz wenn Person eine komplizierte Entität ist. Ich weiß, dass ich Automapper oder etwas verwenden könnte, um die Dinge ein wenig einfacher zu machen, aber dennoch scheint es eine Schande, wenn es keine Möglichkeit gibt, das ursprüngliche Personenobjekt zu speichern, anstatt ein neues zu bekommen und alle Eigenschaften zu kopieren ...

Antwort

1

Der allgemeine Ansatz besteht darin, die Team aus der Datenbank und Add, dass Teams Kollektion zu holen. Die Einstellung EntityState.Modified betrifft nur Skalareigenschaften, nicht Navigationseigenschaften.

+0

kaufen selbst, das scheint nicht zu funktionieren: das Hinzufügen eines Teams geholt von der DB zu einer Person, die Ist kein Proxy, wird die TeamPersons-Tabelle nicht aktualisiert. Was bedeutet Arbeit holt das Team und die Person von der DB (also die Person ist ein Stellvertreter), aber dann müssen Sie diese geholte Person aktualisieren, um der Person zu entsprechen, die gespeichert wird ... – Duncan

+1

Ah, Sie haben Recht (sollte habe besser gelesen). Nach Ihrer Bearbeitung können Sie 'DbContext.Entry (dbPerson) .CurrentValues.SetValues ​​(person)' verwenden. –

+0

Danke, das ist nützlich - ich wusste nichts über CurrentValues.SetValues ​​ – Duncan

0

Versuchen Sie zunächst, die vorhandenen Entitäten auszuwählen und dann das Team mit der Teamkollektion des Personenobjekts zu verknüpfen.

Etwas wie folgt aus: (Syntax vielleicht nicht ganz richtig sein)

using (var context = new TestContext()) 
{ 
    var person = context.Persons.Where(f => f.Id == 1).FirstOrDefault(); 
    var team = context.Teams.Where(f => f.Id == 3).FirstOrDefault(); 

    person.Teams.Add(team); 

    context.Entry(person).State = EntityState.Modified; 
    context.SaveChanges(); 
} 
+0

Danke, aber dann müsste ich diese neue Person aus dem Original aktualisieren, das ich speichern wollte (siehe meine Bearbeitung) - ich hatte gehofft, dass es da wäre ein anderer Weg. – Duncan

+0

Okay, Sie sagen also, dass das Objekt der getrennten Person viele Änderungen enthält? – EkoostikMartin

+0

Möglicherweise, ja: Ich würde gerne wissen, die beste Art der Aktualisierung der DB aus dem getrennten Person-Objekt, wenn es nicht bekannt ist, welche der Eigenschaften dieses Objekts geändert wurden. – Duncan

0

Das ist, wo EF s ** ks. sehr ineffizient für ein getrenntes Szenario. Laden von Daten für das Update/Löschen und jedes für das erneute Anhängen aktualisiert, kann nicht nur die aktualisierte Entität an den Kontext als eine Entität mit dem gleichen Schlüssel möglicherweise bereits im Kontext bereits vorhanden, in diesem Fall, EF wird nur kotzen. Es muss geprüft werden, ob sich eine Entität mit demselben Schlüssel bereits im Kontext befindet und entsprechend angehängt oder aktualisiert wird. Es ist schlimmer, Entity mit vielen bis vielen Beziehungskindern zu aktualisieren. Das Entfernen des gelöschten Kindes stammt vom Entitätssatz des Kindes, aber nicht von der Referenzeigenschaft, es ist sehr unordentlich.

0

Sie können die Attach-Methode verwenden.Versuchen Sie folgendes:

using (var context = new TestContext()) 
{ 
    context.People.Attach(person); 

    //i'm not sure if this foreach is necessary, you can try without it to see if it works 
    foreach (var team in person.Teams) 
    { 
     context.Teams.Attach(team); 
    } 

    context.Entry(person).State = EntityState.Modified; 

    context.SaveChanges(); 
} 

ich diesen Code testen haben, lassen Sie mich wissen, wenn Sie irgendwelche Probleme haben