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

Go To StackoverFlow.com

33

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?

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)

enter image description here

2012-04-03 20:51
by Luke McGregor
Are you using code first or model first - and any more info about the model you have, tables/classes that relate to the error and how is the many-to-many mapped. In case you are using code first, I prefer to do the relation 'manually' so I can control all aspects and avoid similar things. On the other side, referential integrity error is likely to mean just that - I don't think it's the sate of the object, though it could manifest in similar way I guess - NSGaga 2012-04-03 20:59
Im using CodeFirst, my model is really simple, ill post a diagram in a se - Luke McGregor 2012-04-03 21:04
Luke, can you give the CF part, how do you map things - how do your model classes look like, your migrations code? To be able to help any with this - NSGaga 2012-04-04 21:28


45

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. 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. If those values are different the exception is thrown. (Having CurrentLocation as null though is allowed.)

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

2012-07-21 22:45
by Slauma
So how do I set the Locations to the Persons (given the Locations IDs)? In my scenario it's a many to many issue. What's the general solution to this exception, how do I get around it - Shimmy 2013-06-08 21:37
@Shimmy: Either set the FK property only leaving the navigation property as null (which I would do in this case) or ensure that FK property value and PK value of the entity set to the navigation property are the same. But in my understanding this exception cannot occur for many-to-many relationships. It's an exception related to FK associations only and many-to-many relationships are independent associations, not FK associations - Slauma 2013-06-08 22:00
In my scenario I have Categorys and Business. Each business can have multiple Categorys. I have a list of the Category IDs I want to attach, how do I do it - Shimmy 2013-06-08 22:24
@Shimmy: Create stub categories (new Category { Id = id }), attach them to the context, add them to the Business.Categories collection and save changes. But this seems a bit off of this question and answer. Perhaps create a new question to get more focussed answers - Slauma 2013-06-08 23:14
You remember that all the categories pre-exist in the DB before attaching their PKs to each business. Is that right - Shimmy 2013-06-08 23:19
@Shimmy: That's what attaching (context.Categories.Attach(category)) is for: Telling EF that the categories already exist - Slauma 2013-06-08 23:38
let us continue this discussion in chatShimmy 2013-06-08 23:39


6

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). This occurs because the client receives the entire object from the server and bounces it as-is back to the server with minor changes.

On the other hand, the ObjectB.PropertyY had just been changed (this was the reason for the PUT request in the first place).

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.

The solution was simple:

ObjectB.ObjectA = null;

before the SaveChanges() solved this completely.

I hope this helps someone.

2018-01-30 08:08
by Erez Lerner


2

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. Once done the Mapping Details window then said Mappings are not allowed.. It appears that adding the referential constraint leaves any mappings in place.

Thought it may be worth posting in case anyone else is looking for solutions to this error message in the future.

2014-09-19 08:29
by Jason Underhill


1

@LukeMcGregor hi,

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. It's the location object in your scenario. 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.

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.

You will either empty the object when you receive the update request from the user. (= 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.

That's it. It can remain as it is in the database and diagrams.

2017-08-28 08:49
by OkurYazar


1

To add to @Slauma's answer, it isn't just when adding objects to your context. 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. When you edit the CurrentLocationId without updating the CurrentLocation object as well, they become out of sync. This is what causes the exception in this case.

So let's say you needed to update the Person object's CurrentLocationId. We'll assume you pre-fetched the Person data and the Location data.

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();
        }
    }
}
2018-11-07 18:02
by Migit


0

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)

[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());
    }
}
2018-05-30 23:28
by clarence_odbody
Ads