web-dev-qa-db-ja.com

Entity Framework Coreで多対多の関係を保存する

たとえば、3つのクラスがあり、多対多の関係に使用しています。

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; }
}

それらは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);
}

だから、データベースにLibrary2Booksのリストを追加したい:

var library2Books = new List<Library2Books>(/*some sort of initialization*/);

最初にどのエンティティを追加する必要がありますか? BooksまたはLibrary?この保存を行うにはどうすればよいですか?

21
Yurii N.

これは、EF Coreの多対多の関係に対する単純で非常に基本的な質問です。 EF Coreでn..mの完全な例を誰も書いていない理由がわかりません。

コードを変更しました(intとしての主キー)。主キーの文字列が好きではありません。コードをコピーして貼り付けるだけで、すべて正常に動作するはずです。

最初にどのエンティティを追加する必要がありますか?本か図書館か?この保存を行うにはどうすればよいですか?

順序は重要ではありませんが、ここで重要なのはデータのリンクです。データは正しくリンクされている必要があります。コード行間のコメントを参照してください。

ノート:

  • 結合テーブルを表すエンティティクラスのない多対多の関係はまだサポートされていません!結合テーブルが必要です。

  • 多対多の関係は、2つの個別の1対多の関係で構成されます。 = 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();
         }
       }
    }
    

結果

Tables:   Books    |   Libraries      |    Library2Book  |
           1       |      1           |      1   |   1   |
           2       |      -           |      1   |   2   |

質問の著者から編集

多くのエンティティを挿入しようとすると(約300を試しました)、同じキーが既に追加されていますエラーになります。挿入コレクションを小さな部分に分割する必要があります。 100個のエンティティで十分です。

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();
}
40
Bassam Alugili