2013-07-05 16 views
6

Ho un'applicazione MVC che utilizza Entity Framework 5. In alcuni punti ho un codice che crea o aggiorna le entità e quindi devo eseguire un qualche tipo di operazioni sui dati aggiornati . Alcune di queste operazioni richiedono l'accesso alle proprietà di navigazione e non riesco a farle aggiornare.Entity Framework 5 - Aggiorna immediatamente DbContext dopo aver salvato le modifiche

Ecco l'esempio (codice semplificato che ho)

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) 
    } 
} 

L'esempio di cui sopra è per il metodo Create ma ho anche lo stesso problema con il metodo di aggiornamento che è molto simile prende solo il oggetto dal contesto nell'azione GET e lo memorizza utilizzando il metodo Update nell'azione POST.

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; 
} 

Ora ho provato diversi approcci che ho cercato su google o trovato nello stack ma nulla sembra funzionare per me.

Nel mio ultimo tentativo, ho provato a forzare una ricarica dopo aver chiamato il metodo SaveChanges e aver richiesto i dati dal database. Ecco cosa ho fatto.

ho ovewrite il metodo SaveChanges per aggiornare contesto dell'oggetto subito dopo il salvataggio

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

    return rowsNumber; 
} 

Ho provato ottenere i dati oggetto aggiornato con l'aggiunta di questa riga di codice immediatamente dopo SaveChanges chiamata nel mio HTTPCreate e Update azioni:

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

Purtroppo la proprietà di navigazione è ancora null. Come posso aggiornare correttamente DbContext subito dopo aver modificato i dati?

EDIT

ho dimenticato di menzionare in origine che so una soluzione, ma è brutto e non mi piace. Ogni volta che utilizzo la proprietà di navigazione posso verificare se è null e se è possibile posso creare manualmente nuovo DbContext e aggiornare i dati. Ma mi piacerebbe davvero evitare gli hack come questo.

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; 
     } 
    } 
} 

risposta

4

Il problema è probabilmente dovuto al fatto che l'elemento che si sta aggiungendo al contesto non è un proxy con tutti i componenti necessari per il caricamento pigro. Anche dopo aver chiamato SaveChanges() l'articolo non sarà convertito in un'istanza con proxy.

Ti suggerisco di provare a utilizzare DbSet.Creare il metodo() e copiare in tutti i valori dalla entità che si riceve sul filo:

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

UPDATE

Se SetValues() sta dando un problema allora vi consiglio di provare automapper di trasferire la dati dall'entità passata nell'entità al proxy creato prima della Add immissione della nuova istanza proxy su DbSet. Qualcosa di simile a questo:

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

E la mia 'metodo Update'? Devo anche recuperare l'oggetto originale diverso da 'this.Context.Cars.Find (id)'? – RaYell

+0

Il 'Find' restituirà un oggetto proxy dal database, ma se stai cercando e aggiornando un oggetto che è stato aggiunto localmente durante questa transazione, troverà l'oggetto che hai aggiunto. – qujck

+0

Ho provato a seguire la tua soluzione ma questo mi ha portato a 'System.InvalidOperationException: membro 'CurrentValues' non può essere chiamato per l'entità di tipo 'Car' perché l'entità non esiste nel contesto. Per aggiungere un'entità al contesto chiama il metodo Add o Attach di DbSet . 'Ho aggiunto' this.Context.Set () .Attach (newEntry); 'subito dopo la prima riga e ora sto ottenendo' System.InvalidOperationException: la proprietà 'Id' è parte delle informazioni chiave dell'oggetto e non può essere modificata. – RaYell

0

io uso la prossima soluzione: staccare entità e caricare di nuovo

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); 
} 
Problemi correlati