【问题标题】:Entity Framework: A referential integrity constraint violation on many to many relationship实体框架:违反多对多关系的参照完整性约束
【发布时间】:2012-04-17 13:47:52
【问题描述】:

嘿,我有一个包含一堆 inproc 缓存和实体框架的应用程序。当我想向实体写入更新时,我会重新附加缓存的副本。我会跟踪我在上下文生命周期中附加的所有内容,因此我不会尝试将它们附加两次。

我在附加时发生错误(在大多数情况下很少会正常工作并且非常快),其中显示以下内容:

发生了参照完整性约束违规:属性 定义引用约束的值不一致 关系中的主体对象和依赖对象之间的关系。

我已经非常仔细地查看了看起来正常的实体。我认为这个问题是由于修复运行时外键的附加/分离造成的。

是否有一种好方法可以获取有关此错误的更多信息,或者它是否会由于实体处于 EF 未预料到的状态之外的其他原因而发生?

编辑: DB 图表(注意我使用的是 codefirst,我只是使用 EDMX 工具制作图表,为简单起见,我还从模型中删除了一堆常规属性)

【问题讨论】:

  • 您是先使用代码还是先使用模型 - 以及有关您拥有的模型、与错误相关的表/类以及多对多映射方式的更多信息。如果您首先使用代码,我更喜欢“手动”执行关系,这样我可以控制所有方面并避免类似的事情。另一方面,参照完整性错误可能意味着——我不认为这是对象的状态,尽管我猜它可能以类似的方式表现出来。
  • 我用的是CodeFirst,我的模型很简单,一会发图
  • Luke,你能给出 CF 部分吗,你是如何映射的——你的模型类是什么样的,你的迁移代码?能够帮助任何人。

标签: c# entity-framework


【解决方案1】:

尝试将任何子类对象设置为 null MainObject.SubObject1 = null; 人.地址=空; // 地址对象为 null 而不是 id

【讨论】:

    【解决方案2】:

    要添加到@Slauma 的答案,不仅仅是将对象添加到您的上下文中。对于您的示例,如果您在 Person 中编辑 CurrentLocationId,您还需要编辑嵌入在 Person 对象中的 CurrentLocation 对象。 EF 将自动填充 CurrentLocation 对象,因为 CurrentLocationId 在 CurrentLocation 的表中有一个外键。当您编辑 CurrentLocationId 而不更新 CurrentLocation 对象时,它们会变得不同步。这就是在这种情况下导致异常的原因。

    假设您需要更新 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();
            }
        }
    }
    

    【讨论】:

      【解决方案3】:

      我刚刚遇到了这个问题,并想出了一个非常快速的解决方案。我的问题是多对多表。

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

      【讨论】:

        【解决方案4】:

        我遇到了一个非常相似的异常:

        "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 的客户端发送了一个包含导航属性的整个对象的 PUT 请求(在此示例中,ObjectA(更准确地说是 ObjectB.ObjectA)是一个导航属性,完全由客户端提供)。发生这种情况是因为客户端从服务器接收到整个对象并将其原样退回到服务器,并进行了微小的更改。

        另一方面,ObjectB.PropertyY 刚刚被更改(这首先是 PUT 请求的原因)。

        由于 ObjectB.PropertyY 是对同一个对象 ObjectA(外键)的引用,EF 尝试对此进行协调,但由于上述异常而失败。

        解决方法很简单:

        ObjectB.ObjectA = null;
        

        在 SaveChanges() 完全解决这个问题之前。

        我希望这对某人有所帮助。

        【讨论】:

          【解决方案5】:

          @LukeMcGregor 嗨,

          我想我可以为遇到同样问题的人提供不同的视角。

          在我执行了所有必要的检查之后,我可以说我更愿意得到这个错误。

          因为在我的场景中:我想包含一个导致不匹配错误的对象。它是您场景中的位置对象。如果我添加一个带有 ID 的对象,我会收到此错误,因为前一个对象(未更新的那个)中的 ID 与更新后的 ID 不匹配。

          但这不是什么大问题。作为解决方案;如果它还在 UI 端,如果它仍然存在,则该对象可能仍然被包含。

          当您收到用户的更新请求时,您将清空对象。 (= Null) 或者您将使用用户在服务端更新之前更新的 ID 更新对象(附加、修改...随便)并以这种方式更新它。

          就是这样。它可以在数据库和图表中保持原样。

          【讨论】:

            【解决方案6】:

            我刚刚遇到同样的问题,我的解决方案是我已将映射添加到关联,然后设置引用约束。

            为了解决这个问题,我必须打开关联的映射窗口,并且有一个链接可以删除映射。一旦完成映射详细信息窗口,然后说映射是不允许的.. 似乎添加引用约束会使任何映射留在原地。

            认为它可能值得发布,以防其他人在未来寻找此错误消息的解决方案。

            【讨论】:

              【解决方案7】:

              除了多对多关系之外,您的模型中显然还有 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。如果这些值不同,则会引发异常。 (尽管允许将 CurrentLocation 用作 null。)

              在我看来,只能为外键关联抛出此异常,因为只有对于这种类型的关联,您才有在模型中定义引用约束的属性。它不能为独立协会抛出。由于每个多对多关系都是一个独立的关联(模型中没有外键属性),我的猜测是错误与您的多对多关系无关,而是与一对多有关。

              【讨论】:

              • 那么如何将Locations 设置为Persons(给定Locations ID)?在我的场景中,这是一个多对多的问题。此异常的一般解决方案是什么,我该如何解决?
              • @Shimmy:要么将 FK 属性设置为仅将导航属性保留为 null(在这种情况下我会这样做),要么确保将实体的 FK 属性值和 PK 值设置为导航属性是一样的。但据我了解,这种异常不会发生在多对多关系中。这是一个仅与 FK 关联相关的例外,并且多对多关系是独立关联,而不是 FK 关联。
              • 在我的场景中,我有 Categorys 和 Business。每个企业可以有多个Categorys。我有一个要附加的类别 ID 列表,我该怎么做?
              • @Shimmy:创建存根类别 (new Category { Id = id }),将它们附加到上下文,将它们添加到 Business.Categories 集合并保存更改。但这似乎有点偏离这个问题和答案。也许创建一个新问题以获得更集中的答案。
              • 您记得在将它们的 PK 附加到每个业务之前,所有类别都预先存在于数据库中。对吗?
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2016-03-16
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多