2013-07-05 26 views
6

Tôi có một ứng dụng MVC sử dụng Entity Framework 5. Ở một vài nơi tôi có một mã để tạo hoặc cập nhật các thực thể và sau đó phải thực hiện một số loại hoạt động trên dữ liệu cập nhật . Một số hoạt động đó yêu cầu truy cập các thuộc tính điều hướng và tôi không thể yêu cầu chúng làm mới.Entity Framework 5 - Ngay lập tức làm mới DbContext sau khi lưu thay đổi

Dưới đây là ví dụ (đơn giản hóa mã mà tôi có)

Models

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

khiển

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

Ví dụ trên là dành cho Create phương pháp nhưng tôi cũng có cùng một vấn đề với phương thức Cập nhật rất giống với phương pháp đối tượng từ ngữ cảnh trong hành động GET và lưu trữ nó bằng cách sử dụng phương thức Update trong hành động 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; 
} 

Bây giờ tôi đã thử một số cách tiếp cận khác nhau mà tôi đã tìm kiếm hoặc tìm thấy trên chồng nhưng dường như không có gì hiệu quả đối với tôi.

Trong lần thử gần đây nhất, tôi đã cố gắng tải lại sau khi gọi phương thức SaveChanges và yêu cầu lại dữ liệu từ cơ sở dữ liệu. Đây là những gì tôi đã làm.

Tôi đã ovewrite các SaveChanges phương pháp để làm mới bối cảnh đối tượng ngay lập tức sau khi lưu

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

    return rowsNumber; 
} 

tôi đã cố gắng nhận được dữ liệu đối tượng được cập nhật bằng cách thêm dòng mã này ngay sau khi SaveChanges cuộc gọi trong HTTP tôi CreateUpdate hành động:

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

Rất tiếc, thuộc tính điều hướng vẫn là null. Làm thế nào tôi có thể làm mới DbContext đúng cách ngay lập tức sau khi sửa đổi dữ liệu?

EDIT

tôi quên đề cập ban đầu mà tôi biết một workaround nhưng nó xấu xí và tôi không thích nó. Bất cứ khi nào tôi sử dụng thuộc tính điều hướng, tôi có thể kiểm tra xem đó là null và liệu tôi có thể tạo DbContext mới và cập nhật dữ liệu theo cách thủ công hay không. Nhưng tôi thực sự muốn tránh hacks như thế này.

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

Trả lời

4

Vấn đề có thể là do mục bạn thêm vào ngữ cảnh không phải là proxy với tất cả các thành phần cần thiết để tải chậm. Ngay cả sau khi gọi SaveChanges() mục này sẽ không được chuyển đổi thành một phiên bản được ủy quyền.

Tôi khuyên bạn nên thử sử dụng DbSet.Tạo() phương pháp và sao chép trên tất cả các giá trị từ các tổ chức mà bạn nhận được qua dây:

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

CẬP NHẬT

Nếu SetValues() được đưa ra một vấn đề sau đó tôi đề nghị bạn thử automapper chuyển dữ liệu từ thực thể được truyền vào proxy được tạo trước khi Add nhập phiên bản proxy mới vào DbSet. Một cái gì đó như thế này:

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

gì về 'phương pháp Update' của tôi? Tôi cũng nên tìm nạp đối tượng gốc khác với 'this.Context.Cars.Find (id)'? – RaYell

+0

'Tìm' sẽ trả về đối tượng proxy từ cơ sở dữ liệu, nhưng nếu bạn đang tìm và cập nhật một đối tượng đã được thêm cục bộ trong giao dịch này, nó sẽ tìm đối tượng bạn đã thêm. – qujck

+0

Tôi đã thử làm theo giải pháp của bạn nhưng điều đó dẫn tôi đến 'System.InvalidOperationException: Thành viên 'CurrentValues' không thể được gọi cho thực thể kiểu 'Xe hơi' vì thực thể không tồn tại trong ngữ cảnh. Để thêm thực thể vào ngữ cảnh, hãy gọi phương thức Thêm hoặc Đính kèm của DbSet .' Tôi đã thêm 'this.Context.Set () .Attach (newEntry);' ngay sau dòng đầu tiên của bạn và bây giờ tôi nhận được ' System.InvalidOperationException: Thuộc tính 'Id' là một phần của thông tin khóa của đối tượng và không thể sửa đổi.' – RaYell

0

tôi sử dụng workaround tiếp theo: tách tổ chức và nạp lại

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