繁体   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