简体   繁体   中英

EF6 Many to many Insert

My problem is to save existing objects that are part of a many-to-many relationship in a code-first database with EF6.

I am receiving objects from a web service and they look (simplified) like:

public class Car
{
    [DataMember]
    public virtual string CarId { get; set; }

    [DataMember]
    public virtual ICollection<Contract> Contracts { get; set; }
}

public class Contract
{   
    [DataMember]
    public virtual string ContractId { get; set; }

    [DataMember]
    public virtual ICollection<Car> Cars { get; set; } 
}

I have a code-first database and set the relationship with:

        modelBuilder.Entity<Contract>().HasKey(t => new {t.ContractId});
        modelBuilder.Entity<Car>().HasKey(t => new {t.CarId})
            .HasMany(c => c.Contracts)
            .WithMany(c => c.Cars)
            .Map(x =>
            {
                x.ToTable("CarContracts");
                x.MapLeftKey("CarId");
                x.MapRightKey("ContractId");
            });

When I get a list of cars I can save the first car and EF creates the relation table and the contracts successfully. On the second car the save fails saying " constraint failed UNIQUE constraint failed: Contracts.ContractId ", since I'm trying to insert a Contract with the same Id as an already existing Contract.

The solutions I found to this problem is to set the Contract in the dbContext to Attached:

foreach (var contract in car.Contracts)
{
    context.Contract.Attach(contract);
}

This throws the same exception as the previous save. When I try to modify the Contract-list of the second car I get a NotSupportedException , the only solution I can think of is recreating the car objects and attach the same Contract-object to them, which seems unnecessarily complicated.

Is there any way to tell EF that my two different Contract-objects actually are the same?

Is there any way to tell EF that my two different Contract-objects actually are the same?

The only way is they actually are the same object. If they are different instances even having all the same data EF won't recognize them as same entity.

So the only solution is to replace all same id contract instances by a single one.

Or simpler: create an explicit entity representing the N:N relation and then simply build a list to insert as follows:

var toInsert = new List<CarContract>();
foreach(var car in cars)
{
    toInsert.AddRange(car.Select(x=>new CarContract {CarId=car.Id,ContractId=x.Id}));
}

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