2013-07-05 11 views
6

Ich habe eine MVC-Anwendung, die Entity Framework 5 verwendet. An einigen Orten habe ich einen Code, der die Entitäten erstellt oder aktualisiert und dann eine Art von Operationen auf den aktualisierten Daten ausführen müssen . Einige dieser Vorgänge erfordern den Zugriff auf Navigationseigenschaften, und ich kann sie nicht zum Aktualisieren abrufen.Entity Framework 5 - Aktualisieren Sie sofort DbContext nach dem Speichern von Änderungen

Hier ist das Beispiel (vereinfachte Code, ich habe)

Modelle

class User : Model 
{ 
    public Guid Id { get; set; } 
    public string Name { get; set; } 
} 

class Car : Model 
{ 
    public Guid Id { get; set; } 
    public Guid DriverId { get; set; } 
    public virtual User Driver { get; set; } 

    [NotMapped] 
    public string DriverName 
    { 
     get { return this.Driver.Name; } 
    } 
} 

-Controller

public CarController 
{ 
    public Create() 
    { 
     return this.View(); 
    } 

    [HttpPost] 
    public Create(Car car) 
    { 
     if (this.ModelState.IsValid) 
     { 
      this.Context.Cars.Create(booking); 
      this.Context.SaveChanges(); 

      // here I need to access some of the resolved nav properties 
      var test = booking.DriverName; 
     } 

     // error handling (I'm removing it in the example as it's not important) 
    } 
} 

Das Beispiel ist oben für das Verfahren erstellen, aber ich habe auch das gleiche Problem mit Update-Methode, die sehr ähnlich ist, dauert es nur die Objekt aus dem Kontext in GET Aktion und speichert es mit Update Methode in POST Aktion.

public virtual void Create(TObject obj) 
{ 
    return this.DbSet.Add(obj); 
} 

public virtual void Update(TObject obj) 
{ 
    var currentEntry = this.DbSet.Find(obj.Id); 
    this.Context.Entry(currentEntry).CurrentValues.SetValues(obj); 
    currentEntry.LastModifiedDate = DateTime.Now; 
} 

Jetzt habe ich verschiedene Ansätze ausprobiert, die ich auf Stapel googeln oder gefunden, aber nichts scheint für mich zu arbeiten.

In meinem letzten Versuch habe ich versucht, ein Neuladen nach dem Aufruf SaveChanges Methode und Requerying der Daten aus der Datenbank. Hier ist, was ich getan habe.

Ich habe ovewrite die SaveChanges Methode Objektkontext aktualisieren sofort nach dem Speichern

public int SaveChanges() 
{ 
    var rowsNumber = this.Context.SaveChanges(); 
    var objectContext = ((IObjectContextAdapter)this.Context).ObjectContext; 
    objectContext.Refresh(RefreshMode.StoreWins, this.Context.Bookings); 

    return rowsNumber; 
} 

Ich habe versucht, indem Sie diese Codezeile unmittelbar nach SaveChanges Anruf in meinen HTTPCreate und Update die aktualisierten Objektdaten bekommen Aktionen:

car = this.Context.Cars.Find(car.Id); 

die Navigationseigenschaft Leider ist noch null. Wie kann ich den DbContext sofort nach dem Ändern der Daten aktualisieren?

EDIT

vergaß ich ursprünglich zu erwähnen, dass ich eine Abhilfe wissen, aber es ist hässlich, und ich mag es nicht. Immer wenn ich die Navigationseigenschaften verwende, kann ich prüfen, ob es null ist. Wenn das der Fall ist, kann ich manuell neuen DbContext erstellen und die Daten aktualisieren. Aber ich möchte solche Hacks wirklich vermeiden. keine proxy mit allen notwendigen Komponenten für verzögertes Laden

class Car : Model 
{  
    [NotMapped] 
    public string DriverName 
    { 
     get 
     { 
      if (this.Driver == null) 
      { 
       using (var context = new DbContext()) 
       { 
        this.Driver = this.context.Users.Find(this.DriverId); 
       } 
      } 

      return this.Driver.Name; 
     } 
    } 
} 

Antwort

4

Das Problem ist wahrscheinlich aufgrund der Tatsache, dass das Element, das Sie auf den Kontext hinzugefügt werden, ist. Auch nach dem Aufruf SaveChanges() wird der Artikel nicht konvertiert in eine Proxy-Instanz.

Ich schlage vor, Sie versuchen, mit dem DbSet.Create() Methode und kopieren Sie über alle Werte von der Einheit, die Sie über den Draht erhalten:

public virtual TObject Create(TObject obj) 
{ 
    var newEntry = this.DbSet.Create(); 
    this.Context.Entry(newEntry).CurrentValues.SetValues(obj); 
    return newEntry; 
} 

UPDATE

Wenn SetValues() ein Problem ist, geben dann schlage ich vor, Sie versuchen, automapper die übertragen Daten von der übergebenen Entität an den erstellten Proxy vor Add der neuen Proxy-Instanz an die DbSet. Etwas wie folgt aus:

private bool mapCreated = false; 
public virtual TObject Create(TObject obj) 
{ 
    var newEntry = this.DbSet.Create(); 

    if (!mapCreated) 
    { 
     Mapper.CreateMap(obj.GetType(), newEntry.GetType()); 
     mapCreated = true; 
    } 
    newEntry = Mapper.Map(obj, newEntry); 

    this.DbSet.Add(newEntry; 
    return newEntry; 
} 
+0

Was ist mit meinem 'Update' Methode? Soll ich auch das ursprüngliche Objekt außer 'this.Context.Cars.Find (id)' holen? – RaYell

+0

Die 'Find' wird ein Proxy-Objekt aus der Datenbank zurückgeben, aber wenn Sie ein Objekt finden und aktualisieren, das während dieser Transaktion lokal hinzugefügt wurde, wird es das Objekt finden, das Sie hinzugefügt haben. – qujck

+0

Ich habe versucht, Ihrer Lösung zu folgen, aber das führte mich zu 'System.InvalidOperationException: Member 'CurrentValues' kann nicht für die Entität vom Typ 'Car' aufgerufen werden, da die Entität im Kontext nicht existiert. Um dem Kontext eine Entität hinzuzufügen, rufen Sie die Add- oder Attach-Methode von DbSet auf. "Ich habe" this.Context.Set () .Attach (newEntry); 'direkt nach Ihrer ersten Zeile hinzugefügt und jetzt bekomme ich' System.InvalidOperationException: Die Eigenschaft 'Id' ist Teil der Schlüsselinformation des Objekts und kann nicht geändert werden.' – RaYell

0

ich nächste Abhilfe verwenden: abzulösen Einheit und laden wieder

public T Reload<T>(T entity) where T : class, IEntityId 
{ 
    ((IObjectContextAdapter)_dbContext).ObjectContext.Detach(entity); 
    return _dbContext.Set<T>().FirstOrDefault(x => x.Id == entity.Id); 
}