2015-11-03 45 views
1

我有兩個表,促進和PromotionLine,被定義爲PromotionLine.PromoID = Promotion.ID如何將更改保存到相關表中MVC 5和6 EF - 實體框架主詳細

PromotionLines是一個外鍵具有促進模型相關聯在促進類以下內容:

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

    } 

這工作,我可以在我看來訪問推廣線。

然而,當我去更新的變化,我遇到的錯誤:

「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.」

我明白爲什麼這個錯誤發生。我不知道如何繞過它。 我使用的是默認的更新方法(由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); 

「這個」 具有推廣線。實體。促銷沒有。

這裏是我如何調用更新方法:

[HttpPost] 
    public ActionResult Edit(Promotion promotion) 
    { 
     if (ModelState.IsValid) 
     { 
      promotion.Update(); 
     } 
     return View(promotion); 
    } 

問題

  • 我如何推廣線添加到entities.Promotions?
  • 或者,我應該以不同的方式接近此更新嗎?
+0

什麼是你的推廣模板編輯樣的? –

+0

有沒有更改孩子列表?例如添加到'PromotionLineItems'的一些項目和'PromotionComments'的一些項目被移除並且......? –

+0

@RezaAghaei - 是的,子列表已更改(例如,PromotionLineItems中的值已更改)。 –

回答

2

這不是一件小事。你需要更新你的對象圖。換句話說,你需要一個Master-Detail更新。

爲了保持簡單的答案,我想我有一個Order實體有OrderDetails屬性,它是一個List<OrderDetail>編輯時。你應該注意:

  • 有一些OrderDetail已添加到OrderDetails和它們中的主要符號具有Id屬性等於0
  • 某些OrderDetail已被刪除並在OrderDetails
  • 某些OrderDetail已經被改變不再存在。

當更新Order時,您應更新Order本身,並應用上述更改。

步驟

通過以下步驟:

  1. 從數據庫中獲得原始訂單。
  2. 使用編輯後的訂單更新原始訂單的價值。
  3. 查找添加項目列表(添加項目的ID爲0)。
  4. 查找已刪除項目的清單(原始訂單詳細信息列表,其中原始訂單詳細信息的編號不在編輯訂單的訂單詳細信息的ID之間)。
  5. 查找已編輯項目的清單(原始訂單明細的編號在已編輯訂單的訂單明細的ID之間的原始訂單的清單)。
  6. 使用循環播放刪除的項目列表並將其設置爲刪除狀態。
  7. 在已編輯的項目列表上使用循環並更新已在上下文中加載的原始訂單詳細信息的值。
  8. 使用循環添加項目列表並設置它們的狀態以添加。
  9. 將原始訂單的狀態設置爲已修改。
  10. 保存上下文更改。

代碼

下面是代碼:

public void Update(Order editedOrder) 
{ 
    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(); 
} 
+0

我使用了問題評論中提供的鏈接Gert,但這是一個類似的方法。我將其標記爲答案,因爲我相信這會幫助其他有類似問題的人。 –

+0

謝謝您的反饋:) –