For example, I have 3 classes, which I'm using for many-to-many relationship:
public class Library { [Key] public string LibraryId { get; set; } public List<Library2Book> Library2Books { get; set; } } public class Book { [Key] public string BookId { get; set; } public List<Library2Book> Library2Books { get; set; } } public class Library2Book { public string BookId { get; set; } public Book Book { get; set; } public string LibraryId { get; set; } public Library Library { get; set; } }
They're configured in ApplicationDbContext
:
protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); builder.Entity<CodeableConcept2Coding>().HasKey(k => new { k.LibraryId, k.BookId }); builder.Entity<Library2Book>() .HasOne(x => x.Library) .WithMany(x => x.Library2Book) .HasForeignKey(x => x.LibraryId); builder.Entity<Library2Book>() .HasOne(x => x.Book) .WithMany(x => x.Library2Book) .HasForeignKey(x => x.BookId); }
So, I want to add to database some list of Library2Books
:
var library2Books = new List<Library2Books>(/*some sort of initialization*/);
What entity should I add first? Books
or maybe Library
? How can I do this saving?
This is a simple and a very fundamental question to EF Core many-to-many relationship; I do not know why no one has written a complete example for n..m in EF Core.
I have modified your code (primary key as int
), I do not like string in primary key. Just copy/paste the code and every should work fine.
What entity should I add first? Books or maybe Library? How can I do this saving?
The order is not important the important thing here is the data linking. The data must be correctly linked, see the comments between my code lines.
Notes:
Many-to-many relationships without an entity class to represent the join table are not yet supported! You must have a join table.
Many-to-many relationships consists of 2 separate one-to-many relationships. = 2x 1:N
class Program { public class Library { [Key] public int LibraryId { get; set; } public List<Library2Book> Library2Books { get; set; } = new List<Library2Book>(); } public class Book { [Key] public int BookId { get; set; } public List<Library2Book> Library2Books { get; set; } = new List<Library2Book>(); } public class Library2Book { [Key] public int BookId { get; set; } public Book Book { get; set; } [Key] public int LibraryId { get; set; } public Library Library { get; set; } } public class MyDbContext : DbContext { public DbSet<Book> Books { get; set; } public DbSet<Library> Libraries { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer(@"Server=.\;Database=EFTutorial;integrated security=True;"); base.OnConfiguring(optionsBuilder); } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Library2Book>().HasKey(k => new { k.LibraryId, k.BookId }); modelBuilder.Entity<Library2Book>() .HasOne(x => x.Book) .WithMany(x => x.Library2Books) .HasForeignKey(x => x.BookId); modelBuilder.Entity<Library2Book>() .HasOne(x => x.Library) .WithMany(x => x.Library2Books) .HasForeignKey(x => x.LibraryId); base.OnModelCreating(modelBuilder); } } static void Main(string[] args) { using (var myDb = new MyDbContext()) { // Create Db myDb.Database.EnsureCreated(); // I will add two books to one library var book1 = new Book(); var book2 = new Book(); // I create the library var lib = new Library(); // I create two Library2Book which I need them // To map between the books and the library var b2lib1 = new Library2Book(); var b2lib2 = new Library2Book(); // Mapping the first book to the library. // Changed b2lib2.Library to b2lib1.Library b2lib1.Book = book1; b2lib1.Library = lib; // I map the second book to the library. b2lib2.Book = book2; b2lib2.Library = lib; // Linking the books (Library2Book table) to the library lib.Library2Books.Add(b2lib1); lib.Library2Books.Add(b2lib2); // Adding the data to the DbContext. myDb.Libraries.Add(lib); myDb.Books.Add(book1); myDb.Books.Add(book2); // Save the changes and everything should be working! myDb.SaveChanges(); } } }
Results
Tables: Books | Libraries | Library2Book | 1 | 1 | 1 | 1 | 2 | - | 1 | 2 |
Edit from author of the question
When you're trying to insert a lot of entities (I've tried approximately 300), you'll have the same key has been already added error. You should split your inserting collection into small parts, e.g. 100 entities should be enough.
public async Task SaveEntities(IEnumerable<Library2Book> library2Books) { int i = 0; foreach (var library2Book in library2Books) { _dbContext.Set<Library>().Add(codConc2Coding.Library); _dbContext.Set<Book>().Add(codConc2Coding.Book); _dbContext.Set<Library2Book>().Add(library2Book); i++; if (i == 99) { await _dbContext.SaveChangesAsync(); i = 0; } } await _dbContext.SaveChangesAsync(); }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With