如何在MVC 5和EF 6中保存对相关表的更改-实体框架主细节
本文关键字:细节 框架 实体 MVC EF 保存 | 更新日期: 2023-09-27 18:20:22
我有两个表,Promotion和PromotionLine,外键定义为PromotionLine.PromoID=Promotion.ID
PromotionLines与Promotion模型相关联,Promotion类中包含以下内容:
public IList<PromotionLine> PromotionLineItems { get; set; }
我选择不使用虚拟,因为如果我们只是使用摘要视图来显示高级促销信息(如促销列表),我不希望加载促销行。
当需要促销详细信息时,我会得到促销线路:
public static Promotion GetInstance(int? promotionId)
{
if (promotionId == null) return null;
using (APP01Entities entities = new APP01Entities())
{
return entities.Promotions
.Include(s => s.PromotionState)
.Include(h => h.PromotionHeaderType)
.Include(l => l.PromotionLineItems)
.Include(c => c.PromotionComments)
.FirstOrDefault(p => p.ID == promotionId);
}
}
这很有效,我可以在我的视图中访问促销线。
然而,当我去更新更改时,我遇到了错误:
"发生引用完整性约束冲突:属性关系一端的"Promotion.ID"的值不匹配另一个的"PromotionLine.PromotionID"的属性值结束。"
我理解为什么会出现这种错误。我不知道如何避开它。我使用默认的更新方法(由EF脚手架创建):
public bool Update()
{
try
{
using (APP01Entities entities = new APP01Entities())
{
entities.Promotions.Attach(this);
var entity = entities.ChangeTracker.Entries<Promotion>().FirstOrDefault(e => e.Entity == this);
if (entity == null)
{
return false;
}
entity.State = EntityState.Modified;
entities.SaveChanges();
}
return true;
}
catch (System.Data.Entity.Validation.DbEntityValidationException e)
{
throw e.Improve();
}
}
问题在于:
entities.Promotions.Attach(this);
"this"有促销语。实体。促销没有。
以下是我如何调用更新方法:
[HttpPost]
public ActionResult Edit(Promotion promotion)
{
if (ModelState.IsValid)
{
promotion.Update();
}
return View(promotion);
}
问题
- 如何将促销线添加到实体中。促销
- 或者,我应该以不同的方式处理此更新吗
这不是一项琐碎的任务。您需要更新对象图。换句话说,你需要一个主细节更新。
为了简单起见,我假设我有一个Order
实体,它具有OrderDetails
属性,即List<OrderDetail>
。编辑时应注意:
- 有一些
OrderDetail
被添加到OrderDetails
中,它们的主符号是具有等于0的Id
性质 - 某些
OrderDetail
已被删除,不再存在于OrderDetails
中 - 某些
OrderDetail
已更改
更新Order
时,应更新Order
本身,并应用上述更改。
步骤
以下是步骤:
- 从数据库中获取原始订单
- 使用编辑后的订单更新原始订单的值
- 查找添加项目的列表(添加项目的Id为0)
- 查找已删除项目的列表(原始订单的订单详细信息列表,其中原始订单详细信息的id不在已编辑订单的订单细节的id之间)
- 查找已编辑项目的列表(原始订单的订单详细信息列表,其中原始订单详细信息的id在已编辑订单的订单细节的id之间)
- 在已删除项目列表上使用循环,并将其状态设置为已删除
- 在已编辑的项目列表上使用循环,并更新已在上下文中加载的原始订单详细信息的值
- 在已添加项目列表上使用循环,并将其状态设置为已添加
- 将原始订单的状态设置为已修改
- 保存上下文更改
代码
这是代码:
public void Update(Order editedOrder)
{
using(var context = new YourDbContext())
{
//Get original order from database.
var originalOrder = context.Orders.Including("OrderDetails")
.Where(x => x.OrderId == editedOrder.OrderId).FirstOrDefault();
//Update the value of original order using edited order.
context.Entry(originalOrder).CurrentValues.SetValues(editedOrder);
//Find list of added items (Id of added items is 0).
var addedList = editedOrder.OrderDetails
.Where(y => y.OrderDetailId == 0).ToList();
//Find list of removed items.
var deletedList = originalOrder.OrderDetails
.Where
(
x =>!editedOrder.OrderDetails.Select(y => y.OrderDetailId)
.Contains(x.OrderDetailId)
)
.ToList();
//Find list of edited items.
var editedList = editedOrder.OrderDetails
.Where
(
y => originalOrder.OrderDetails.Select(z => z.OrderDetailId)
.Contains(y.OrderDetailId)
)
.ToList();
//Use a loop over deleted items list and set state of them to removed.
deletedList.ForEach(deletedDetail =>
{
originalOrder.OrderDetails.Remove(deletedDetail);
context.Entry(editedOrder).State = EntityState.Deleted;
});
//Use a loop over edited items list
//and update value of original order details that have been loaded in context.
editedList.ForEach(editedDetail =>
{
var originalOrderDetail = originalOrder.OrderDetails
.Where(x => x.OrderDetailId == editedDetail.OrderDetailId)
.FirstOrDefault();
context.Entry(originalOrderDetail).CurrentValues.SetValues(editedDetail);
});
//Use a loop over added items list and set state of them to added.
addedList.ForEach(addedDetail =>
{
originalOrder.OrderDetails.Add(addedDetail);
});
//Set the state of original order to modified.
context.Entry(oroginalOrder).State = System.Data.Entity.EntityState.Modified;
//Save context changes.
context.SaveChanges();
}
}