Entity framework 实体框架5-保存更改后立即刷新DbContext
我有一个使用EntityFramework5的MVC应用程序。在少数地方,我有一个创建或更新实体的代码,然后必须对更新的数据执行某种操作。其中一些操作需要访问导航属性,我无法让它们刷新 下面是一个示例(我有简化的代码) 型号Entity framework 实体框架5-保存更改后立即刷新DbContext,entity-framework,entity-framework-5,dbcontext,Entity Framework,Entity Framework 5,Dbcontext,我有一个使用EntityFramework5的MVC应用程序。在少数地方,我有一个创建或更新实体的代码,然后必须对更新的数据执行某种操作。其中一些操作需要访问导航属性,我无法让它们刷新 下面是一个示例(我有简化的代码) 型号 class User : Model { public Guid Id { get; set; } public string Name { get; set; } } class Car : Model { public Guid Id { ge
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; }
}
}
控制器
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)
}
}
上面的例子是针对Create方法的,但我也有与Update方法相同的问题,它非常类似,它只是从GET
操作中的上下文中获取对象,并使用Update
方法将其存储在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;
}
现在我已经尝试了几种不同的方法,我在谷歌上搜索或者在stack上找到了这些方法,但似乎什么都不适合我
在我最近的尝试中,我尝试在调用SaveChanges
方法并从数据库中重新查询数据后强制重新加载。这就是我所做的
我已经编写了SaveChanges
方法来在保存后立即刷新对象上下文
public int SaveChanges()
{
var rowsNumber = this.Context.SaveChanges();
var objectContext = ((IObjectContextAdapter)this.Context).ObjectContext;
objectContext.Refresh(RefreshMode.StoreWins, this.Context.Bookings);
return rowsNumber;
}
我已尝试通过在我的HTTP
Create
和Update
操作中的SaveChanges
调用后立即添加此行代码来获取更新的对象数据:
car = this.Context.Cars.Find(car.Id);
不幸的是,导航属性仍然是null
。如何在修改数据后立即正确刷新DbContext
编辑
我忘了最初提到我知道一个解决方法,但它很难看,我不喜欢它。无论何时使用navigation属性,我都可以检查它是否为null
,如果是,我可以手动创建新的DbContext并更新数据。但我真的很想避免这样的黑客攻击
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;
}
}
}
问题可能是因为您添加到上下文中的项不是具有延迟加载所需所有组件的
代理。即使在调用SaveChanges()
之后,该项也不会转换为代理实例
我建议您尝试使用DbSet.Create()方法,并跨通过线路接收的实体的所有值进行复制:
public virtual TObject Create(TObject obj)
{
var newEntry = this.DbSet.Create();
this.Context.Entry(newEntry).CurrentValues.SetValues(obj);
return newEntry;
}
更新
如果SetValues()
出现问题,那么我建议您在将新代理实例添加到DbSet
之前,尝试将数据从传入实体传输到创建的代理。大概是这样的:
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;
}
我使用下一个解决方法:分离实体并再次加载
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);
}
public T重载(T实体),其中T:class,IEntityId
{
((IObjectContextAdapter)dbContext.ObjectContext.Detach(实体);
返回_dbContext.Set().FirstOrDefault(x=>x.Id==entity.Id);
}
我的更新方法如何?除了this.Context.Cars.Find(id)
之外,我还应该获取原始对象吗?Find
将从数据库返回一个代理对象,但是,如果您正在查找和更新在此事务期间本地添加的对象,它将查找您添加的对象。我尝试按照您的解决方案进行操作,但这导致我出现System.invalidoOperationException:无法为“Car”类型的实体调用成员“CurrentValues”,因为该实体在上下文中不存在。要向上下文添加实体,请调用DbSet的add或Attach方法。
我已经添加了this.context.Set().Attach(newEntry)代码>就在您的第一行之后,现在我得到了System.InvalidOperationException:属性“Id”是对象关键信息的一部分,无法修改。
@Colin我考虑过这个选项,但它使答案变得复杂,因为如果没有公开Id属性的公共基类/接口,它就不是泛型的。@qujck则此解决方案需要公开Id属性的基类。我假设提问者也必须有这个,因为Car和User都实现了Model,并且在Update方法中引用了obj.Id。我发现我的模型有一个基类在其他方面也非常有用,但我相信它并不适合所有人,所以感谢您强调这一点。