2012-10-19 26 views
2

更新實體我有以下型號實體框架,參照完整性約束衝突發生錯誤從斷開區域

public class Order 
{ 
    [Key] 
    public virtual string OrderNo {get;set;} 
    public virtual IList<OrderItem> Items {get;set;} 
} 

public class OrderItem 
{ 
    [Key] 
    public virtual string ItemNo {get; set;} 
    public virtual string ParentItemNo {get;set;} 
    public virtual string OrderNo {get;set;} 

    public virtual OrderItem ParentItem {get;set;} 
    public virtual IList<OrderItem> ChildItems {get;set;} 
    public virtual IList<ItemProperty> ItemProperties {get;set;} 
    public virtual Order Order {get;set;} 
} 

public class ItemProperty 
{ 
    [Key] 
    public virtual string PropertyNo {get; set;} 
    public virtual string ParentPropertyNo {get;set;} 
    public virtual string OrderItemNo {get;set;} 

    public virtual ItemProperty ParentProperty {get;set;} 
    public virtual IList<ItemProperty> ChildProperties {get;set;} 
    public virtual OrderItem OrderItem {get;set;} 
} 

我上斷開區域(從實體框架方面與我們的服務斷開)運行

  1. 我創建了一個訂單,並保存到數據庫

客戶端:

service.CreateOrder(new Order() { OrderN="fksjdf1" }); 

服務器:

using(EfDbContext context = new EfDbContext()) 
{ 
    context.Orders.Add(order); 
    context.SaveChanges(); 
} 
  1. 我需要一個或一個以上的OrderItems添加到以前添加的順序

客戶端:

var order = service.GetOrder("fksjdf1"); 

var item1 = new OrderItem(); 
item1.ItemNo="i1"; 
item1.Order=order; 
item1.OrderNo=order.OrderNo; 
item1.ItemProperties.Add(new ItemProperty() 
    PropertyNo="p1", 
    OrderItem = item1 
}) 
order.Items.Add(item1); 

var item2 = new OrderItem(); 
item2.ItemNo="i2"; 
item2.Order=order; 
item2.OrderNo=order.OrderNo; 
item2.ItemProperties.Add(new ItemProperty() 
    PropertyNo="p2", 
    OrderItem = item2 
}); 
item2.ItemProperties.Add(new ItemProperty() 
    PropertyNo="p3", 
    OrderItem = item2 
}) 
order.Items.Add(item2); 
service.UpdateOrder(order); 

服務器:

using(EfDbContext context = new EfDbContext()) 
{ 
    DbEntityEntry dbEntityEntry = context.Entry(order); 
    if (dbEntityEntry.State == EntityState.Detached) 
    { 
     // ERROR 
     context.Set<Order>().Attach(order); 
    } 

    dbEntityEntry.State = EntityState.Modified; 
    context.SaveChanges(); 
} 

錯誤:發生參照完整性約束違規:定義參照約束的屬性值在關係中的主體和從屬對象之間不一致。

爲什麼我看到這個錯誤?爲什麼我不更新這個實體?

如何從斷開連接的區域使用實體框架?

編輯1:

public Order GetOrder(string orderNo) 
{ 
using (EfDbContext context = new EfDbContext()) 
      { 
       context.Configuration.ProxyCreationEnabled = false; 
       var order = context.Orders 
        .Include(o => o.OrderItems 
             .Select(z => z.ItemProperties 
                 .Select(y => y.ChildProperties))) 
                 .Where(o => o.OrderNo == orderNo) 
        .FirstOrDefault(); 
      } 
} 
+0

你能證明你的代碼service.GetOrder()?使用上面的代碼,它不會產生錯誤(除非您正在爲您檢索的訂單進行更改OrderNo) –

+0

@Mark Oreta,我分享了我的GetOrder函數 – oguzh4n

回答

2

你可能有這樣的錯誤,因爲你不設置OrderItemNoItemProperty,像這樣:

var item1 = new OrderItem(); 
item1.ItemNo="i1"; 
item1.Order=order; 
item1.OrderNo=order.OrderNo; 
item1.ItemProperties.Add(new ItemProperty { 
    PropertyNo="p1", 
    OrderItem = item1, 
    OrderItemNo = item1.ItemNo // = "i1" 
}); 
order.Items.Add(item1); 

// and the same for item2 

當訂單被附加到上下文,相關命令項目和項目屬性也被附加。導航屬性OrderItemItemProperty是指使用您提供的密鑰("i1")的實體,但外鍵OrderItemNo沒有此密鑰值。這是異常抱怨的不一致。

編輯

不幸的是不那麼容易更新數據庫中分離對象圖。將實體的狀態設置爲Modified僅將此實體標記爲Modified,並且不包含相關實體。

您的GetOrder方法使事情變得複雜,因爲您急切地將已經存在的項目和更多相關的東西加載到客戶端,然後在客戶端添加新的OrderItem,並將此新的修改的對象圖發送回服務器。在服務器端,您現在有一個問題,即必須以不同的方式(將它們插入到數據庫中)處理已有的項目(不要將它們插入到數據庫中)。要做到這一點,你需要檢測哪些項目是舊的,哪些是新的。如果您不在實體本身中傳輸指示實體是否爲新實體的某個標誌,則必須再次查詢數據庫,並將從DB加載的對象圖與從客戶端發送的分離對象圖進行比較。一般草圖如何做到這裏:https://stackoverflow.com/a/5540956/270591(這隻適用於有孩子收藏的父母,如果涉及孫子藏品 - 就像在你的模特里一樣 - 它會變得越來越複雜)。

在我看來,你可以簡化整個過程如果不僅有全局service.UpdateOrder(order)方法試圖處理對象圖中的所有可能的變化,而且還有一些利用關於圖的變化的知識的專門方法 - 在這種情況下是用於添加新的OrderItem s到現有的訂單。它看起來是這樣的:

var order = service.GetOrder("fksjdf1"); 

var newOrderItems = new List<OrderItem>(); 

var item1 = new OrderItem(); 
item1.ItemNo="i1"; 
item1.OrderNo=order.OrderNo; // leave the Order property null 
item1.ItemProperties.Add(new ItemProperty { PropertyNo="p1" }); 
newOrderItems.Add(item1); 

// the same for item2 
newOrderItems.Add(item2); 

service.AddNewOrderItems(newOrderItems); 

,服務方法是:

public void AddNewOrderItems(List<OrderItem> newOrderItems) 
{ 
    using(EfDbContext context = new EfDbContext()) 
    { 
     foreach (var newOrderItem in newOrderItems) 
      context.Set<OrderItem>().Add(newOrderItem); 

     context.SaveChanges(); 
    } 
} 
+0

這不會被設置當他設置關係時,因爲他將實體添加到item1.ItemProperties中? –

+1

@MarkOreta:我不這麼認爲。在客戶端,他只是構建了一個沒有上下文支持的POCO對象圖。在服務器端,他將該對象圖添加到上下文中。我不認爲EF會調整FK屬性,因爲它不知道什麼是正確的:FK值或相關實體?我認爲這是例外的意思。 – Slauma

+0

@Slauma,我試着添加OrderItemNo,代碼不在「context.Set ().Attach(order);」行但沒有改變我的數據庫,EF無法處理我的更改。 – oguzh4n

相關問題