Asp.net mvc 3 实体框架更新导航实体
我正在使用EntityFramework4.1开发一个ASP.NETMVC3Web应用程序,但是,我在更新实体的导航实体时遇到了一个问题 我有一个叫做移位的实体Asp.net mvc 3 实体框架更新导航实体,asp.net-mvc-3,entity-framework,entity-framework-4.1,Asp.net Mvc 3,Entity Framework,Entity Framework 4.1,我正在使用EntityFramework4.1开发一个ASP.NETMVC3Web应用程序,但是,我在更新实体的导航实体时遇到了一个问题 我有一个叫做移位的实体 public partial class Shift { public Shift() { this.Locations = new HashSet<ShiftLocation>(); } public int shiftID { get; set; } public
public partial class Shift
{
public Shift()
{
this.Locations = new HashSet<ShiftLocation>();
}
public int shiftID { get; set; }
public string shiftTitle { get; set; }
public virtual ICollection<ShiftLocation> Locations { get; set; }
}
ShiftService类中的UpdateShift方法如下所示
public partial class ShiftLocation
{
public int shiftLocationID { get; set; }
public int shiftID { get; set; }
public int locationID { get; set; }
public virtual Shift Shift { get; set; }
}
public void UpdateShift(Shift item)
{
_UoW.Shifts.Update(item);
_UoW.Commit();
}
然后调用我的通用存储库中的Update方法
public void Update(TEntity entityToUpdate)
{
dbSet.Attach(entityToUpdate);
context.Entry(entityToUpdate).State = EntityState.Modified;
}
第二次编辑
根据Slauma的回答,我将我的EditShift Post操作编辑为
if (ModelState.IsValid)
{
//Shift shift = new Shift();
Shift shift = _shiftService.GetShiftByID(model.shiftID);
ShiftLocation shiftLocation = shift.Locations.Where(s => s.shiftID == model.shiftID).Single();
shift = Mapper.Map<ViewModelShift, Shift>(model);
shiftLocation.locationID = model.locationID;
shift.Locations.Add(shiftLocation);
_shiftService.UpdateShift(shift);
return RedirectToAction("Index");
}
现在,我知道为什么会发生这种情况,因为在我的EditPost操作中,我正在检索移位的一个实例,然后在通用存储库中的Update方法中,我尝试附加相同的移位
我现在真的很困惑。我的通用Repositor看起来不错,因为我是从本文顶部提到的MicrosoftMVC教程中复制的
再次感谢您对如何使此简单更新生效的任何帮助。请参考您的评论 当我到达“编辑班次”后操作时,我想更新“班次” 使用从传入的中检索的新详细信息 “ViewModelShift模型”。此ViewModel还将包含 “locationID”仅用于1“移位位置”,但是,此移位位置 数据库中已经存在,我只想用新的 locationID 。。。我会尝试以下方法(省略您的存储库结构): 将
shift
的状态设置为Modified
无效,因为它不会影响任何相关实体。该位置仍将处于状态未更改
。您还可以将位置的状态设置为Modified
,但在ViewModel中似乎没有主键属性shiftLocationID
。因此,找到要更新的正确位置的唯一方法是通过shift的导航属性加载它(Include
,在上面的示例中)
编辑
第二次编辑中的代码不起作用,因为AutoMapper创建了一个新的shift
实例,然后将此shift附加到上下文中。但是,由于您已经从数据库中加载了shift
,因此该shift
也会附加到上下文中。不能将具有相同键的两个不同实例附加到上下文。这导致了异常
我上面的代码应该可以工作,我尝试使用您的服务和通用存储库重写它。这两者都必须扩展,因为服务和存储库似乎没有足够丰富的功能来执行任务。尤其是通用的Update
太弱,无法更新对象图(根对象+一个或多个导航属性)
在通用存储库中查找
方法:
public IQueryable<T> Find(Expression<Func<T, bool>> predicate,
params Expression<Func<T, object>>[] includes)
{
return dbSet.IncludeMultiple(includes)
.Where(predicate);
}
// "Flat" means: Scalar and Complex properties, but not Navigation properties
public void UpdateFlatProperties(T attachedEntity, T detachedEntity)
{
context.Entry(attachedEntity).CurrentValues.SetValues(detachedEntity);
}
能否显示
移位位置
类和移位服务.UpdateShift(shift)
中的代码?@Slauma-请查看我的编辑。谢谢你。你到底想达到什么目的?假设shift
存储在数据库中,并且已经在数据库中为其分配了5个shiftlocation
。现在,您进入EditShift
post操作。在代码中创建一个ShiftLocation
对象,并将其添加到shift.Locations
集合中。您现在是否要:1)将此新位置作为编号6添加到现有位置,或2)是否要删除5个现有位置并将其替换为新位置,或3)是否要将该位置作为5个位置之一(按Id?)进行查找,然后使用新值进行更新?@Slauma-当我到达“EditShift”后期操作时,我想用从传入的“ViewModelShift模型”中检索的新详细信息更新“Shift”。此ViewModel还将仅包含1个“ShiftLocation”的“locationID”,但是,数据库中已经存在此ShiftLocation,我只想用新的locationID更新它。这有意义吗?谢谢。@Slauma-是否需要加载相关的ShiftLocation,即在执行update语句之前附加到Shift?请参阅上面我的第二次编辑。还有什么好主意吗?谢谢。@tgriffiths:您能在第二次编辑时再次检查代码吗?不知何故,这毫无意义:您正在将shiftLocation
添加到shift.Locations
集合中,但从之前完全相同的集合中检索了此shiftLocation
。另外,您实例化了一个新的位置
,但没有对该实例执行任何操作。我删除了实例化的“位置”,因为它没有执行任何操作。我将“shiftLocation”添加到shift.Locations,因为我的AutoMapper不为我这样做。一旦Mapper.Map代码运行,shift.Locations=0,因此我将使用新更新的“locationID”将shiftLocation添加到shift.Locations。但问题仍然存在,即在执行更新时ObjectStateManager中已经存在密钥。我非常感谢您在这方面所做的工作。你的新编辑看起来不错,我将在我的解决方案中实现它。谢谢
[HttpPost]
public ActionResult EditShift(ViewModelShift model)
{
if (ModelState.IsValid)
{
Shift shift = context.Shifts
.Include(s => s.Locations)
.Single(s => s.shiftID == model.shiftID);
context.Entry(shift).CurrentValues.SetValues(model);
ShiftLocation location = shift.Locations.Single();
// because you expect exactly one location
location.locationID = model.locationID;
context.SaveChanges();
return RedirectToAction("Index");
}
//...
}
[HttpPost]
public ActionResult EditShift(ViewModelShift model)
{
if (ModelState.IsValid)
{
Shift shift = Mapper.Map<ViewModelShift, Shift>(model);
_shiftService.UpdateShiftAndLocation(shift, model.LocationID);
return RedirectToAction("Index");
}
//...
}
public void UpdateShiftAndLocation(Shift detachedShift, int locationID)
{
Shift attachedShift = _UoW.Shifts.Find(
s => s.ShiftID == detachedShift.ShiftID, s => s.Locations);
_UoW.Shifts.UpdateFlatProperties(attachedShift, detachedShift);
ShiftLocation location = attachedShift.Locations.Single();
// MUST be exactly one location for the Shift in the DB
// ToDo: Catch the case somehow, if there is no or more than one location
location.LocationID = locationID;
_UoW.Commit();
}
public IQueryable<T> Find(Expression<Func<T, bool>> predicate,
params Expression<Func<T, object>>[] includes)
{
return dbSet.IncludeMultiple(includes)
.Where(predicate);
}
// "Flat" means: Scalar and Complex properties, but not Navigation properties
public void UpdateFlatProperties(T attachedEntity, T detachedEntity)
{
context.Entry(attachedEntity).CurrentValues.SetValues(detachedEntity);
}