簡體   English   中英

實體框架:對多對多關系的參照完整性約束違反

[英]Entity Framework: A referential integrity constraint violation on many to many relationship

嘿,我有一個帶有大量進程內緩存和實體框架的應用程序。 當我想對實體進行更新時,我會重新附加緩存的副本。 我跟蹤我在上下文的生命周期中附加的所有東西,所以我不會嘗試附加它們兩次。

我在附加時發生錯誤(在大多數情況下很少見,這工作正常並且非常快),它說以下內容:

發生引用完整性約束沖突:定義引用約束的屬性值在關系中的主體對象和依賴對象之間不一致。

我仔細查看了看起來很正常的實體。 我認為這個問題是由於修復運行時外鍵的附加/分離造成的。

有沒有一種好方法可以獲取有關此錯誤的更多信息,或者它是否可以由於實體位於 state 而不是 EF 預期的其他原因而發生?

編輯:數據庫圖(注意我使用的是 codefirst 我只是使用 EDMX 工具來制作圖表,為了簡單起見,我還從 model 中刪除了一堆常規屬性)

在此處輸入圖像描述

除了多對多關系之外,您顯然在 model 中擁有的PersonLocation之間的一對多關系可能會發生錯誤。 例如下面的代碼會拋出異常:

using (var context = new MyContext())
{
    var person = new Person
    {
        CurrentLocationId = 1,
        CurrentLocation = new Location { Id = 2 }
    };
    context.People.Attach(person); // Exception
}

“定義引用約束的屬性值”是外鍵屬性值CurrentLocationId和主鍵值CurrentLocation.Id 如果這些值不同,則拋出異常。 (雖然CurrentLocationnull是允許的。)

在我看來,只能為外鍵關聯拋出此異常,因為只有對於這種類型的關聯,您才具有在 model 中定義引用約束的屬性。它不能為獨立關聯拋出。 由於每個多對多關系都是一個獨立的關聯(模型中沒有外鍵屬性),我的猜測是錯誤與您的多對多關系無關,而是與一對多關系有關。

我遇到了一個非常相似的異常:

"A referential integrity constraint violation occurred: 
The property value(s) of 'ObjectA.PropertyX' on one end of a relationship 
do not match the property value(s) of 'ObjectB.PropertyY' on the other end."

原因是這樣的:web API 的客戶端發送了一個包含整個 object 的 PUT 請求,包括導航屬性(在此示例中,ObjectA(更准確地說是 ObjectB.ObjectA)是一個導航屬性,完全由客戶端提供)。 發生這種情況是因為客戶端從服務器接收到整個 object 並將其按原樣彈回服務器並進行微小更改。

另一方面,ObjectB.PropertyY 剛剛被更改(這是 PUT 請求的首要原因)。

由於 ObjectB.PropertyY 是對同一個 object ObjectA(外鍵)的引用,因此 EF 嘗試對此進行協調,但因上述異常而失敗。

解決方案很簡單:

ObjectB.ObjectA = null;

在 SaveChanges() 完全解決這個問題之前。

我希望這可以幫助別人。

我剛剛遇到了同樣的問題,我的解決方案是我已將映射添加到關聯,然后設置引用約束。

為了解決這個問題,我必須打開關聯的映射 window,並且有一個刪除映射的鏈接。 一旦完成映射詳細信息 window 然后說不允許映射。添加引用約束似乎會留下任何映射。

認為可能值得發布,以防其他人將來尋找此錯誤消息的解決方案。

@LukeMcGregor 嗨,

我想我可以提供與有同樣問題的人不同的觀點。

在我執行了所有必要的檢查之后,我可以說我更願意得到這個錯誤。

因為在我的場景中:我想包含一個導致不匹配錯誤的 object。 它是您場景中的位置 object。 如果我添加一個帶有 ID 的 object,我會收到此錯誤,因為之前的 object(未更新的那個)中的 ID 與更新后的 ID 不匹配。

但這不是什么大問題。 作為解決方案; 如果還在UI端,object如果還存在的話,可能還是會被包含進去。

當您收到用戶的更新請求時,您將清空 object。 (= Null) 或者,您將使用用戶在服務端更新(附加、修改...等等)之前更新的 ID 更新 object,並以這種方式更新它。

而已。 它可以保持數據庫和圖表中的原樣。

要添加到@Slauma 的答案,不僅僅是在將對象添加到您的上下文時。 對於您的示例,如果您在 Person 中編輯 CurrentLocationId,則還需要編輯 Person object 中嵌入的 CurrentLocation object。EF 將自動填充 CurrentLocation object,因為 CurrentLocationId 在 CurrentLocation 的表中有一個外鍵。 當您在不更新 CurrentLocation object 的情況下編輯 CurrentLocationId 時,它們會變得不同步。 這就是導致本例異常的原因。

因此,假設您需要更新 Person 對象的 CurrentLocationId。 我們假設您預取了 Person 數據和 Location 數據。

public class DbData 
{
    List<Person> PersonList;
    List<Location> LocationList;
    public DbData()
    {
        using (var context = new MyContext())
        {
             PersonList = context.Persons.ToList();
             LocationList = context.Locations.ToList();
        }
    }

    public void UpdatePersonLocation(Person person, int newLocationId)
    {
        using (var context = new MyContext())
        {
            var location = LocationList.Where(l=>l.id==newLocationId).Single();
            //you need to update both the id and the location for this to not throw the exception
            person.CurrentLocationId == newLocationId;
            person.CurrentLocation == location;  
            context.Entry(person).State = System.Data.Entity.EntityState.Modified;
            context.SaveChanges();
        }
    }
    //or if you're giving it the location object...
    public void UpdatePersonLocation(Person person, Location location)
    {
        using (var context = new MyContext())
        {
            //you need to update both the id and the location for this to not throw the exception
            person.CurrentLocationId == location.id;
            person.CurrentLocation == location;  
            context.Entry(person).State = System.Data.Entity.EntityState.Modified;
            context.SaveChanges();
        }
    }
}

我剛遇到這個問題,想出了一個非常快速的解決方案。 我的問題是一張多對多表。

Public class Pictures_Tag
{
    [Key]
    [Column(Order = 0)]
    [ForeignKey("Picture")]
    public Int16 Picture_ID { get; set; }
    [Key]
    [Column(Order = 1)]
    [ForeignKey("ImageTag")]
    public Int16 ImageTag_ID { get; set; }
    public virtual Picture Picture { get; set; }
    public virtual ImageTag ImageTag { get; set; }
}

我在分配Picture = db.Pictures...的位置添加了行,然后它工作正常(不確定為什么)

[HttpPost]
public ActionResult Edit2(WebSiteEF2017C.Models.Pictures_Tag p)
{     
    using (var db = new thisModel(Session["org"].ToString())
    {
         p.Picture = db.Pictures.Where(z => z.ID == p.Picture_ID).FirstOrDefault();
         db.Pictures_Tags.Attach(p);
         db.Entry(p).State = EntityState.Modified;
         db.SaveChanges();
         return View(db.Pictures_Tags.Include(x => x.Picture)
                    .Where(n => n.Picture_ID == p.Picture_ID & n.ImageTag_ID == p.ImageTag_ID).FirstOrDefault());
    }
}

嘗試將任何子 class object 設置為 null MainObject.SubObject1 = null; Person.Address=null; // 地址 Object 為 null 而不是 id

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM