[英]How to save changes to related table in MVC 5 and EF 6 - Entity Framework Master-Detail
I have two tables, Promotion and PromotionLine, with a foreign key defined as PromotionLine.PromoID = Promotion.ID我有两个表,Promotion 和 PromotionLine,外键定义为 PromotionLine.PromoID = Promotion.ID
PromotionLines are associated with the Promotion model with the following in the Promotion class: PromotionLines 与 Promotion 模型相关联,在 Promotion 类中具有以下内容:
public IList<PromotionLine> PromotionLineItems { get; set; }
I chose not to use virtual because I don't want the promo lines loaded if we're just using a summary view to show high level Promotion info (such as a list of Promotions).我选择不使用虚拟,因为如果我们只是使用摘要视图来显示高级促销信息(例如促销列表),我不希望加载促销行。
When promotion details are needed, I get the promotion lines:当需要促销详细信息时,我会得到促销行:
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);
}
}
This works, and I can access the promotion lines in my view.这有效,我可以在我的视图中访问促销行。
However, when I go to update changes, I encounter the error:但是,当我去更新更改时,我遇到了错误:
“A referential integrity constraint violation occurred: The property value(s) of 'Promotion.ID' on one end of a relationship do not match the property value(s) of 'PromotionLine.PromotionID' on the other end.” “发生了参照完整性约束违规:关系一端的‘Promotion.ID’的属性值与另一端‘PromotionLine.PromotionID’的属性值不匹配。”
I understand WHY this error is occurring.我明白为什么会发生这个错误。 I don't know how to get around it.我不知道如何绕过它。 I'm using the default update method (created by EF scaffolding):我正在使用默认更新方法(由 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();
}
}
The problem is with:问题在于:
entities.Promotions.Attach(this);
"this" has the promotion lines. “这”有宣传线。 entities.Promotions does not. entity.Promotions 没有。
Here is how I'm calling the update method:这是我调用更新方法的方式:
[HttpPost]
public ActionResult Edit(Promotion promotion)
{
if (ModelState.IsValid)
{
promotion.Update();
}
return View(promotion);
}
Questions问题
This is not a trivial task.这不是一项微不足道的任务。 You need to update your object graph.您需要更新对象图。 In other word you need a Master-Detail update.换句话说,您需要主从更新。
To keep the answer simple I suppose I have an Order
entity that have OrderDetails
property that is a List<OrderDetail>
.You should pay attention when editing:为了简单OrderDetails
,我想我有一个Order
实体,它有一个List<OrderDetail>
OrderDetails
属性。编辑时应该注意:
OrderDetail
that have been added to OrderDetails
and the main sign of them is having Id
property equal to 0.有一些OrderDetail
已添加到OrderDetails
,它们的主要标志是Id
属性等于 0。OrderDetail
have been removed and no longer exist in OrderDetails
一些OrderDetail
已被删除,不再存在于OrderDetails
OrderDetail
have been changed.一些OrderDetail
已更改。 When updating the Order
you should update the Order
itself and also apply above changes.更新Order
您应该更新Order
本身并应用上述更改。
Steps脚步
Here are steps:以下是步骤:
Code代码
Here is the code:这是代码:
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();
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.