简体   繁体   中英

Entity Framework 6 with Database-First Many to Many relationship problem

I'm having a bit of a problem with EF 6 DB first using a many-to-many relationship schema. Here's an simplified example:

public partial class Person
{
    public int Id { get; set; }
    public string Name{ get; set; }
    public virtual ICollection<Car> Cars { get; set; }
}

public partial class Car
{
    public Car()
    {
        this.People = new HashSet<Person>();
        this.Tires = new HashSet<Tire>();
    }

    public int Id { get; set; }
    public string Model{ get; set; }
    public string Make { get; set; }
    public virtual ICollection<Person> People { get; set; }
    public virtual ICollection<Tire> Tires { get; set; }
}

public partial class Tire
{
    public Tire()
    {
        this.Cars = new HashSet<Car>();
    }

    public string Model{ get; set; }
    public int Size { get; set; }
    public virtual ICollection<Car> Cars{ get; set; }
}

There are five tables in the DB for this:

Person
PersonCarMapping
Car
CarTireMapping
Tire

Three tables to store data and two tables to map/associate the data. My problem happens when I create a Person object, populate it with data, and try to save it.

A person might have multiple cars and a car might have different model tires, hence the many-to-many mapping. If I create a Person object, with multiple cars, BUT with several of those cars having the same Model tire (the PK of the Tire table), EF doesn't check first to see if that Tire model is already a part of this Person object (by association), and it tries to add it two or more times to the Tire table. In reality, only the mapping table needed to be modified to show a new mapping between Car and (already existing) Tire.

So after building a Person object, with multiple cars, cars with multiple tires, etc. and trying:

context.Person.Add(personObject)
context.SaveChanges();

Gives a primary key violation error on the Tire table. What am I missing?
EF seems to handle deletes OK by only deleting from the mapping tables but additions are giving me problems.

[edit]
I'm going to switch this up a bit because I found a solution for my original issue but a similar one popped up.

Here's how I would build a couple of person objects:

Person p1 = new Person() { Id = 1, Name = "Joe" }
Car car1 = new Car() { Id = 1, Make = "Honda", Model = "Accord" } 
Car car2 = new Car() { Id = 2, Make = "Honda", Model = "Civic" }
Tire tire1 = new Tire() { Model = "ModelA", Size = 16 }
car1.Tires.Add(tire1);
p1.Cars.Add(car1);
p1.Cars.Add(car2);

Person p2 = new Person() { Id = 2, Name = "Bob" }
Car car3 = new Car() { Id = 1, Make = "Honda", Model = "Accord" } 
p1.Cars.Add(car3);

// Finally
context.Person.Add(p1);
context.SaveChanges();   // Necessary to save twice.  Don't ask.

context.Person.Add(p2);
context.SaveChanges();

This throws a primary key violation because it tries to add a Car of Id 1 when saving p2. Is there a way to make EF smart enough to realize that only the association table needs to be added to and that the Car table itself doesn't need to be touched because a Car with ID 1 already exists in the Car table?

you can specify the entity state before calling SaveChanges.

context.Entry(existingCar).State = EntityState.Unchanged;


EF deals with references. Two different references to an object with the same key are not treated as the same thing:

Person p1 = new Person() { Id = 1, Name = "Joe" }
Car car1 = new Car() { Id = 1, Make = "Honda", Model = "Accord" } 
p1.Cars.Add(car1);

Person p2 = new Person() { Id = 2, Name = "Bob" }
Car car3 = new Car() { Id = 1, Make = "Honda", Model = "Accord" } 
p2.Cars.Add(car3);

Car 1 & 3 are two separate references but meant to point at car ID=1. I think you had a bug in your example which had p1.Cars.Add(car3) instead of p2. Either way, the issue is with the two car instances. Instead:

Person p2 = new Person() { Id = 2, Name = "Bob" }
p2.Cars.Add(car1);

Now car ID 1 will be correctly referenced between Person 1 and Person 2.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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