2013-07-05 8 views
6

Mam aplikację MVC, która korzysta z Entity Framework 5. W kilku miejscach mam kod, który tworzy lub aktualizuje podmioty, a następnie musi wykonać jakieś operacje na zaktualizowanych danych . Niektóre z tych operacji wymagają dostępu do właściwości nawigacji i nie mogę ich odświeżyć.Entity Framework 5 - Natychmiast odśwież DbContext po zapisaniu zmian

Oto przykład (uproszczony kod, który mam)

modele

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

Powyższy przykład jest dla metody Create, ale ja też mam ten sam problem z metodą aktualizacji, która jest bardzo podobna, po prostu bierze obiekt z kontekstu w akcji GET i przechowuje go przy użyciu metody Update w akcji.

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

Teraz próbowałem kilka różnych podejść, że google lub znalezione na stosie, ale nic nie wydaje się działać dla mnie.

W mojej ostatniej próbie spróbowałem wymusić przeładowanie po wywołaniu metody SaveChanges i przesłaniu danych z bazy danych. Oto co zrobiłem.

mam ovewrite metody SaveChanges odświeżyć kontekst obiektu natychmiast po zapisać

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

    return rowsNumber; 
} 

Próbowałem uzyskanie zaktualizowanych danych obiektu przez dodanie tej linii kodu natychmiast po SaveChanges rozmowy w moim HTTPCreate i Update Działania:

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

Niestety, właściwość nawigacji nadal jest null. Jak mogę poprawnie odświeżyć DbContext natychmiast po modyfikacji danych?

EDIT

zapomniałem wspomnieć, że pierwotnie wiem obejście, ale jest brzydki i nie podoba. Ilekroć używam właściwości nawigacji, mogę sprawdzić, czy jest to null, a jeśli tak, mogę ręcznie utworzyć nowy DbContext i zaktualizować dane. Ale naprawdę chciałbym uniknąć takich hacków.

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

Odpowiedz

4

Problemem jest to prawdopodobnie ze względu na fakt, że element jest dodawany do kontekstu nie jest proxy we wszystkie niezbędne składniki dla leniwych załadunku. Nawet po wywołaniu SaveChanges() element nie będzie przekształcany w instancję proxy.

Proponuję spróbować użyć DbSet.Tworzenie metody() i skopiować na wszystkich wartości od podmiotu, który otrzymasz na drucie:

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

UPDATE

Jeśli SetValues() daje problem to proponuję spróbować automapper aby przenieść dane z przekazanego obiektu do utworzonego serwera proxy przed Add dla nowej instancji proxy do DbSet. Coś takiego:

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

Co o moim 'metody Update'? Czy powinienem również pobrać oryginalny obiekt inny niż 'this.Context.Cars.Find (id)'? – RaYell

+0

'Znajdź' zwróci obiekt proxy z bazy danych, ale jeśli znajdujesz i aktualizujesz obiekt, który został dodany lokalnie podczas tej transakcji, to znajdzie dodany obiekt. – qujck

+0

Próbowałem podążać za rozwiązaniem, ale to doprowadziło mnie do "System.InvalidOperationException: Member" CurrentValues ​​"nie można wywołać dla encji typu" Car ", ponieważ podmiot nie istnieje w kontekście. Aby dodać obiekt do kontekstu, należy wywołać metodę Add lub Attach z DbSet . "Dodałem' this.Context.Set () .Attach (newEntry); 'zaraz po twojej pierwszej linii i teraz otrzymuję' System.InvalidOperationException: Właściwość "Id" jest częścią kluczowych informacji obiektu i nie można jej modyfikować. " – RaYell

0

używam następny obejście: odłączyć jednostkę i załadować ponownie

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