[英]EF adding entity: The relationship could not be changed because one or more of the foreign-key properties is non-nullable
[英]The relationship could not be changed because one or more of the foreign-key properties is non nullable
在使用EF更新期間出現以下錯誤:
操作失敗:無法更改關系,因為一個或多個外鍵屬性不可為空。 當對關系進行更改時,相關的外鍵屬性將設置為空值。 如果外鍵不支持空值,則必須定義新關系,必須為外鍵屬性分配另一個非空值,或者必須刪除不相關的對象。
有沒有一般的方法來查找哪些外鍵屬性導致上述錯誤?
[更新]
對於以下代碼導致上述錯誤的一種情況(我在斷開連接的環境中工作,所以我使用graphdiff
來更新我的對象圖),當它想要運行_uow.Commit();
:
public void CopyTechnicalInfos(int sourceOrderItemId, List<int> targetOrderItemIds)
{
_uow = new MyDbContext();
var sourceOrderItem = _uow.OrderItems
.Include(x => x.NominalBoms)
.Include("NominalRoutings.NominalSizeTests")
.AsNoTracking()
.FirstOrDefault(x => x.Id == sourceOrderItemId);
var criteria = PredicateBuilder.False<OrderItem>();
foreach (var targetOrderItemId in orderItemIds)
{
int id = targetOrderItemId;
criteria = criteria.OR(x => x.Id == id);
}
var targetOrderItems = _uow.OrderItems
.AsNoTracking()
.AsExpandable()
.Where(criteria)
.ToList();
foreach (var targetOrderItem in targetOrderItems)
{
//delete old datas and insert new datas
targetOrderItem.NominalBoms = sourceOrderItem.NominalBoms;
targetOrderItem.NominalBoms.ForEach(x => x.Id = 0);
targetOrderItem.NominalRoutings = sourceOrderItem.NominalRoutings;
targetOrderItem.NominalRoutings.ForEach(x => x.Id = 0);
targetOrderItem.NominalRoutings
.ForEach(x => x.NominalTests.ForEach(y => y.Id = 0));
targetOrderItem.NominalRoutings
.ForEach(x => x.NominalSizeTests.ForEach(y => y.Id = 0));
_uow.OrderItems.UpdateGraph(targetOrderItem,
x => x.OwnedCollection(y => y.NominalBoms)
.OwnedCollection(y => y.NominalRoutings,
with => with
.OwnedCollection(t => t.NominalTests)));
}
_uow.Commit();
}
在Entity Framework中,您可以使用外鍵關聯 。 也就是說,另一個對象的外鍵表示為一對兩個屬性:原始外鍵屬性(例如NominalRouting.OrderItemId
)和對象引用( NominalRouting.OrderItem
)。
這意味着您可以設置原始值或對象引用以建立外鍵關聯。 如果您設置其中一個,EF會盡可能保持另一個同步。 不幸的是,這也可能引起原始外鍵值與其伴隨參考之間的沖突。
很難說出你的情況究竟發生了什么。 不過,我不知道你從一個父母的另一個“復制”對象的方法是......不理想。 首先,更改主鍵值絕不是一個好主意。 通過將它們設置為0
您可以使對象看起來像新的,但它們不是。 其次,您將多個相同的子對象分配給其他父對象。 我認為 ,作為一個結果,你最終得到大量具有外鍵值 ,但不是一個參考對象。
我說“復制”,因為那是你看似試圖實現的。 如果是這樣,您應該正確克隆對象並將它們Add
到每個targetOrderItem
。 與此同時,我想知道為什么你(顯然)克隆所有這些對象。 看起來多對多關聯在這里更合適。 但這是一個不同的主題。
現在你的實際問題是: 如何找到沖突的關聯?
這非常非常困難。 它需要代碼來搜索概念模型並找到涉及外鍵關聯的屬性。 然后你必須找到他們的價值觀並發現不匹配。 與確定可能的沖突何時是真正的沖突相比,這很難,但是微不足道。 讓我通過兩個例子來澄清這一點。 這里, OrderItem
類具有由Order
和OrderId
屬性組成的必需外鍵關聯。
var item = new OrderItem { OrderId = 1, ... };
db.OrderItems.Add(item);
db.SaveChanges();
所以有一個分配了OrderId
和Order
= null的項目,EF很高興。
var item = db.OrderItems.Include(x => x.Order).Find(10);
// returns an OrderItem with OrderId = 1
item.Order = null;
db.SaveChanges();
同樣,分配了OrderId
且Order
= null的項目,但EF拋出異常“關系無法更改...”。
(還有更多可能的沖突情況)
因此,在OrderId/Order
對中查找不匹配的值是不夠的,您還必須檢查實體狀態並確切地知道不允許不匹配的狀態組合。 我的建議:忘記它,修復你的代碼。
雖然有一個骯臟的伎倆。 當EF嘗試匹配外鍵值和引用,某處的嵌套樹深跌if
的IT收集我們談論到的一個成員變量沖突ObjectStateManager
,命名_entriesWithConceptualNulls
。 通過做一些反思可以獲得它的價值:
#if DEBUG
db.ChangeTracker.DetectChanges(); // Force EF to match associations.
var objectContext = ((IObjectContextAdapter)db).ObjectContext;
var objectStateManager = objectContext.ObjectStateManager;
var fieldInfo = objectStateManager.GetType().GetField("_entriesWithConceptualNulls", BindingFlags.Instance | BindingFlags.NonPublic);
var conceptualNulls = fieldInfo.GetValue(objectStateManager);
#endif
conceptualNulls
是一個HashSet<EntityEntry>
, EntityEntry
是一個內部類,因此您只能檢查調試器中的集合以了解沖突的實體。 僅用於診斷目的!!!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.