2012-09-13 9 views
5

Ich mache eine MVC4 Web-Anwendung mit Entity Framework 5 (Datenbank-zuerst mit generierten POCOs) für den Datenzugriff.Wie kann ich eine POCO-Struktur von Entity Framework 5 ordnungsgemäß wieder anfügen und speichern?

In der App durchläuft der Benutzer mehrere Bildschirme, in denen er ein Dokument erstellt oder bearbeitet ("Fallstudie" genannt). Wenn sie auf dem letzten Bildschirm ankommen, ist ihr Dokument als CaseStudy POCO im Speicher vorhanden und alles ist großartig, bis es Zeit ist, diese Struktur in der Datenbank zu speichern.

Um das Dokument zu speichern, habe ich mehrere Datenbanktabellen definiert, die wiederum den von der Business-Schicht verwendeten EF POCOs zugeordnet sind, die dann von den MVC-Controllern verwendet werden. Als solche werden kurzlebige DbContexte verwendet, um POCOs abzurufen und sie in einer Sitzung zwischen Anforderungen zu speichern.

Als Ergebnis muss der Sicherungsbildschirm den Inhalt dieses POCO mit Navigationseigenschaften zu vorhandenen Tabellendaten (Kategorien-, Layout- und Abschnittstabellen) und auch hinzugefügte oder aktualisierte Daten (CaseStudySections und CaseStudy selbst) speichern. So sind alle POCOs entweder neu oder der Kontext, der verwendet wird, um sie wiederzugewinnen, wurde lange entsorgt. Mit anderen Worten, sie sind alle "losgelöst".

Was an diesem Post ungewöhnlich ist, ist, dass ich bereits eine funktionierende Lösung in der Hand habe. Das Problem ist, dass es sperrig, spröde und unelegant ist. Ich poste den Code unten. Man beachte die Iteration durch Untersammlungen, die expliziten Adds und Attaches, das Erlangen eines Eintragsobjekts und das Markieren einzelner Eigenschaften als modifiziert, nur damit sie aktualisiert werden, und der schreckliche Song und Tanz am Ende, um die AdditionalMaterials-Sammlung synchronisiert zu bekommen. Wenn dies erforderlich ist, um mit abgetrennten POCOs in EF5 fertig zu werden, werde ich enttäuscht sein.

Fehle ich hier etwas? Entspricht dies den Best Practices? Gibt es eine elegantere und/oder prägnantere Möglichkeit, eine Struktur von POCOs anzuhängen und einzufügen/zu aktualisieren?

Der Code eine Fallstudie speichern:

public void SaveCaseStudy(CaseStudy caseStudy) 
{ 
    foreach (var s in caseStudy.CaseStudySections) 
    { 
     this.Entities.Sections.Attach(s.Section); 

     if (s.CreatedByRefId == default(Guid)) 
     { 
      s.CreatedByRefId = this.UserRefId; 
      s.CreatedTime = DateTime.Now; 
      this.Entities.CaseStudySections.Add(s); 
     } 
     else 
     { 
      this.Entities.CaseStudySections.Attach(s); 
      var entry = this.Entities.Entry(s); 
      entry.Property(e => e.TextData).IsModified = true; 
      entry.Property(e => e.BinaryData).IsModified = true; 
     } 

     s.LastModifiedByRefId = this.UserRefId; 
     s.LastModifiedTime = DateTime.Now; 
    } 

    foreach (var m in caseStudy.AdditionalMaterials) 
    { 
     if (m.CreatedByRefId == default(Guid)) 
     { 
      m.CreatedByRefId = this.UserRefId; 
      m.CreatedTime = DateTime.Now; 
      this.Entities.AdditionalMaterials.Add(m); 
     } 
     else 
     { 
      this.Entities.AdditionalMaterials.Attach(m); 
     } 

     m.LastModifiedByRefId = this.UserRefId; 
     m.LastModifiedByTime = DateTime.Now; 
    } 

    this.Entities.Layouts.Attach(caseStudy.Layout); 
    this.Entities.Categories.Attach(caseStudy.Category); 

    if (caseStudy.CreatedByRefId != default(Guid)) 
    { 
     this.Entities.CaseStudies.Attach(caseStudy); 
     var entry = this.Entities.Entry(caseStudy); 
     entry.Property(e => e.CaseStudyName).IsModified = true; 
     entry.Property(e => e.CaseStudyTitle).IsModified = true; 
    } 
    else 
    { 
     this.Entities.CaseStudies.Add(caseStudy); 
     caseStudy.CreatedByRefId = this.UserRefId; 
     caseStudy.CreatedTime = DateTime.Now; 
    } 

    caseStudy.LastModifiedByRefId = this.UserRefId; 
    caseStudy.LastModifiedTime = DateTime.Now; 

    if (caseStudy.CaseStudyStatus != (int)CaseStudyStatus.Personalized) 
    { 
     caseStudy.CaseStudyStatus = (int)CaseStudyStatus.PendingApproval; 
    } 

    caseStudy.ApprovedByRefId = null; 
    caseStudy.ApprovedTime = null; 
    this.Entities.SaveChanges(); 

    var existingAdditionalMaterialRefIds = caseStudy.AdditionalMaterials 
     .Select(m => m.AdditionalMaterialRefId) 
     .ToArray(); 

    var additionalMaterialsToRemove = this.Entities.AdditionalMaterials 
     .Where(m => 
      m.CaseStudyRefId == caseStudy.CaseStudyRefId && 
      !existingAdditionalMaterialRefIds.Contains(m.AdditionalMaterialRefId)) 
     .ToArray(); 

    foreach (var additionalMaterialToRemove in additionalMaterialsToRemove) 
    { 
     this.Entities.AdditionalMaterials.Remove(additionalMaterialToRemove); 
    } 

    this.Entities.SaveChanges(); 
} 

Antwort

3

Im Allgemeinen ist es, was Sie tun müssen. Sie müssen EF über jede Änderung informieren, die Sie ausführen möchten, wenn Sie das Diagramm für losgelöste Objekte anhängen. Ich sage nicht, dass Ihr Code nicht vereinfacht werden kann, aber Sie müssen immer noch mit jeder Entität umgehen und ihren Status festlegen, wenn Sie möchten, dass sie hinzugefügt oder geändert wird.

Here ist etwas älter, aber immer noch gültige Antwort auf das Thema - kurz gesagt hat sich nichts geändert, seit ich es geschrieben habe, nur neue DbContext API erstellt wurde, die immer noch auf der alten API sitzt. Die beste Beschreibung dieses Themas, die ich bisher gesehen habe, ist in Buch Programming Entity Framework: DbContext.

2

Wie wäre es gerade tun:

db.CaseStudies.Attach(caseStudy); 
db.Entry(caseStudy).State = EntityState.Modified; 
db.SaveChange(); 

Das wird alle Änderungen in Ihrem Modell der db speichern.

+0

Dies funktioniert leider nicht. In unserem Fall führt dies zu einer DbUpdateConcurrencyException: Die Anweisung zum Speichern von Aktualisierungen, Einfügungen oder Löschungen hat eine unerwartete Anzahl von Zeilen (0) betroffen. Entitäten wurden möglicherweise geändert oder gelöscht, seit Entitäten geladen wurden. Aktualisieren Sie die ObjectStateManager-Einträge.' Dies liegt wahrscheinlich daran, dass die caseStudy aus Datenobjekten besteht, von denen einige bereits in der Datenbank vorhanden sind (und daher anscheinend explizit wieder angehängt werden müssen), und einige sind neu und müssen eingefügt werden. –

Verwandte Themen