Search code examples
entity-framework-coreef-code-first

Entity Framework Core code first many-to-many save with only foreign keys


I have a many-to-many relationship established code-first that works, with thousands of fake records generated for an API. Now I'm trying to save a new record on one side of that relationship given only the ids of the other side, as the client is passing in an array of int ids.

I've found plenty of questions with problems and answers about saving many-to-many in general, but none specifically about doing so with just a list of foreign keys. Perhaps I'm simply using the wrong terminology?

I could grab all the records for those ids up front, but it seems very heavy to wait for a database query, assign those entities to the new entity, and then go to the database again to save, when all I really need is to establish a relationship with ids I already have.

For single relationships I would just add the foreign key as a separate property and set that instead of the foreign entity itself:

public int? CarId { get; set; }
[ForeignKey("CarId")]
public CarModel? Car { get; set; }

Is there perhaps a similar paradigm for many-to-many?

Entity setup:

public class ClownModel {
    public int Id { get; set; }
    public List<CarModel> Cars { get; set; }
}
public class CarModel {
    public int Id { get; set; }
    public List<ClownModel> Clowns { get; set; }
}

DB Context OnModelCreating:

builder.Entity<ClownModel>()
    .HasMany(x => x.Cars)
    .WithMan(x => x.Clows);

Solution

  • You can use a "stub entity" to add an existing Car to a new or existing Clown without fetching the Car. Eg

    var newClown = new Clown();
    
    var car = new Car() { Id = carId };
    db.Entry(car).State = EntityState.Unchanged;
    
    newClown.Cars.Add(car);
    
    db.Set<Clown>().Add(newClown);
    db.SaveChanges();
    

    Or include the linking entity in your model, which you can do without adding a DbSet property or changing the Many-to-Many navigation properties.

    eg

    builder.Entity<Clown>()
            .HasMany(x => x.Cars)
            .WithMany(x => x.Clowns)
            .UsingEntity<ClownCar>(
                c => c.HasOne(x => x.Car)
                      .WithMany()
                      .HasForeignKey(x => x.CarId),
                c => c.HasOne(c => c.Clown)
                      .WithMany()
                      .HasForeignKey(c => c.ClownId)
                      );
    

    then

    var newClown = new Clown();
    
    var clownCar = new ClownCar();
    clownCar.CarId = carId;
    clownCar.Clown = newClown;
    
    db.Set<ClownCar>().Add(clownCar);
    db.SaveChanges();