简体   繁体   English

实体框架:对多对多关系的参照完整性约束违反

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

Hey I have an application with a bunch of inproc caching and entity framework.嘿,我有一个带有大量进程内缓存和实体框架的应用程序。 When I want to write an update to an entity I reattach the cached copy.当我想对实体进行更新时,我会重新附加缓存的副本。 I track all things I've attached in the life cycle of the context so I don't try to attach them twice.我跟踪我在上下文的生命周期中附加的所有东西,所以我不会尝试附加它们两次。

I have an error occurring on attach (very rarely in most cases this works fine and is really fast) which says the following:我在附加时发生错误(在大多数情况下很少见,这工作正常并且非常快),它说以下内容:

A referential integrity constraint violation occurred: The property values that define the referential constraints are not consistent between principal and dependent objects in the relationship.发生引用完整性约束冲突:定义引用约束的属性值在关系中的主体对象和依赖对象之间不一致。

I've taken a really careful look at the entity which looks normal.我仔细查看了看起来很正常的实体。 I think this issue is due to the attachment/detachment of a foreign key when fixups runs.我认为这个问题是由于修复运行时外键的附加/分离造成的。

Is there a good way to get any more info on this error or can it occur for reasons other than that the entity was in a state which EF wasnt expecting?有没有一种好方法可以获取有关此错误的更多信息,或者它是否可以由于实体位于 state 而不是 EF 预期的其他原因而发生?

EDIT: DB Diagram (note i'm using codefirst I just used the EDMX tool to make the diagram, I've also chopped a bunch of regular properties off the model for simplicity)编辑:数据库图(注意我使用的是 codefirst 我只是使用 EDMX 工具来制作图表,为了简单起见,我还从 model 中删除了一堆常规属性)

在此处输入图像描述

The error could occur for the one-to-many relationship between Person and Location you apparently have in your model in addition to the many-to-many relationship.除了多对多关系之外,您显然在 model 中拥有的PersonLocation之间的一对多关系可能会发生错误。 For example the following code would throw the exception:例如下面的代码会抛出异常:

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

"The property values that define the referential constraints" are the foreign key property value CurrentLocationId and the primary key value CurrentLocation.Id . “定义引用约束的属性值”是外键属性值CurrentLocationId和主键值CurrentLocation.Id If those values are different the exception is thrown.如果这些值不同,则抛出异常。 (Having CurrentLocation as null though is allowed.) (虽然CurrentLocationnull是允许的。)

In my opinion this exception can only be thrown for foreign key associations because only for this type of association you have properties that define referential constraints at all in your model. It cannot be thrown for independent associations.在我看来,只能为外键关联抛出此异常,因为只有对于这种类型的关联,您才具有在 model 中定义引用约束的属性。它不能为独立关联抛出。 Since every many-to-many relationship is an independent association (no foreign key property in the model) my guess is that the error is not related to your many-to-many relationship, but to the one-to-many.由于每个多对多关系都是一个独立的关联(模型中没有外键属性),我的猜测是错误与您的多对多关系无关,而是与一对多关系有关。

I came across a very similar exception:我遇到了一个非常相似的异常:

"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."

The reason was this: The client side of the web API sent a PUT request with the entire object including the navigation property (in this example ObjectA (more correctly ObjectB.ObjectA) was a navigation property and was fully supplied by the client).原因是这样的:web API 的客户端发送了一个包含整个 object 的 PUT 请求,包括导航属性(在此示例中,ObjectA(更准确地说是 ObjectB.ObjectA)是一个导航属性,完全由客户端提供)。 This occurs because the client receives the entire object from the server and bounces it as-is back to the server with minor changes.发生这种情况是因为客户端从服务器接收到整个 object 并将其按原样弹回服务器并进行微小更改。

On the other hand, the ObjectB.PropertyY had just been changed (this was the reason for the PUT request in the first place).另一方面,ObjectB.PropertyY 刚刚被更改(这是 PUT 请求的首要原因)。

Since ObjectB.PropertyY was a reference to the same object ObjectA (a foreign key), EF tried to reconcile this and failed with the above exception.由于 ObjectB.PropertyY 是对同一个 object ObjectA(外键)的引用,因此 EF 尝试对此进行协调,但因上述异常而失败。

The solution was simple:解决方案很简单:

ObjectB.ObjectA = null;

before the SaveChanges() solved this completely.在 SaveChanges() 完全解决这个问题之前。

I hope this helps someone.我希望这可以帮助别人。

I have just been experiencing the same issue and the resolution to mine was that I had added mappings to the association and then setup the referential contstraints.我刚刚遇到了同样的问题,我的解决方案是我已将映射添加到关联,然后设置引用约束。

Inorder to resolve the issue I had to open the mappings window for the association and there was a link to delete the mappings.为了解决这个问题,我必须打开关联的映射 window,并且有一个删除映射的链接。 Once done the Mapping Details window then said Mappings are not allowed.. It appears that adding the referential constraint leaves any mappings in place.一旦完成映射详细信息 window 然后说不允许映射。添加引用约束似乎会留下任何映射。

Thought it may be worth posting in case anyone else is looking for solutions to this error message in the future.认为可能值得发布,以防其他人将来寻找此错误消息的解决方案。

@LukeMcGregor hi, @LukeMcGregor 嗨,

I think I can offer a different perspective as someone who has the same problem.我想我可以提供与有同样问题的人不同的观点。

After I have performed all the necessary checks, I can say that I prefer to get this error.在我执行了所有必要的检查之后,我可以说我更愿意得到这个错误。

Because in my scenario: I wanted to include an object that caused a mismatch error.因为在我的场景中:我想包含一个导致不匹配错误的 object。 It's the location object in your scenario.它是您场景中的位置 object。 If I add an object with an ID, I get this error because the ID in the previous object (the one that is not updated) does not match the updated ID.如果我添加一个带有 ID 的 object,我会收到此错误,因为之前的 object(未更新的那个)中的 ID 与更新后的 ID 不匹配。

But it's not a big problem.但这不是什么大问题。 As a solution;作为解决方案; If it is still on the UI side, the object may still be included if it still exists.如果还在UI端,object如果还存在的话,可能还是会被包含进去。

You will either empty the object when you receive the update request from the user.当您收到用户的更新请求时,您将清空 object。 (= Null) Or you will update the object with the ID updated by the user before the service-side update (attach, modified... whatever) and update it in this way. (= Null) 或者,您将使用用户在服务端更新(附加、修改...等等)之前更新的 ID 更新 object,并以这种方式更新它。

That's it.而已。 It can remain as it is in the database and diagrams.它可以保持数据库和图表中的原样。

To add to @Slauma's answer, it isn't just when adding objects to your context.要添加到@Slauma 的答案,不仅仅是在将对象添加到您的上下文时。 For your example, if you edit the CurrentLocationId in Person, you also need to edit the CurrentLocation object embedded in the Person object. EF will automatically populate the CurrentLocation object because CurrentLocationId has a foreign key in the CurrentLocation's table.对于您的示例,如果您在 Person 中编辑 CurrentLocationId,则还需要编辑 Person object 中嵌入的 CurrentLocation object。EF 将自动填充 CurrentLocation object,因为 CurrentLocationId 在 CurrentLocation 的表中有一个外键。 When you edit the CurrentLocationId without updating the CurrentLocation object as well, they become out of sync.当您在不更新 CurrentLocation object 的情况下编辑 CurrentLocationId 时,它们会变得不同步。 This is what causes the exception in this case.这就是导致本例异常的原因。

So let's say you needed to update the Person object's CurrentLocationId.因此,假设您需要更新 Person 对象的 CurrentLocationId。 We'll assume you pre-fetched the Person data and the Location data.我们假设您预取了 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();
        }
    }
}

I just had this problem and came up with a pretty quick solution.我刚遇到这个问题,想出了一个非常快速的解决方案。 My issue was with a many-many table.我的问题是一张多对多表。

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

I added the line where I assigned Picture = db.Pictures... and then it worked fine (not exactly sure why)我在分配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());
    }
}

try to set any sub class object to null MainObject.SubObject1 = null;尝试将任何子 class object 设置为 null MainObject.SubObject1 = null; Person.Address=null; Person.Address=null; // Address Object to be null not id // 地址 Object 为 null 而不是 id

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM