【问题标题】:Saving many-to-many relationship in Entity Framework Core在 Entity Framework Core 中保存多对多关系
【发布时间】:2016-12-18 01:06:00
【问题描述】:

例如,我有 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?我怎样才能做到这一点?

【问题讨论】:

    标签: c# many-to-many entity-framework-core


    【解决方案1】:

    这是一个关于 EF Core 多对多关系的简单且非常基础的问题;我不知道为什么没有人在 EF Core 中为 n..m 编写完整的示例。

    我修改了你的代码(主键为int),我不喜欢主键中的字符串。只需复制/粘贴代码,每个都可以正常工作。

    我应该先添加什么实体?书籍或图书馆?我怎样才能做到这一点?

    顺序不重要,重要的是数据链接。数据必须正确链接,查看我的代码行之间的 cmets。

    注意事项:

    • 尚不支持没有实体类来表示连接表的多对多关系!您必须有一个连接表。

    • 多对多关系由 2 个独立的一对多关系组成。 = 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();
    }
    

    【讨论】:

    • 感谢您的回答!但我有疑问。澄清一些事情。所以,正如你所说,如果顺序不重要,如果我有var library2Books = new List&lt;Library2Books&gt;(),我可以像这样将它添加到数据库中:myDb.Libraries.Add(library2Books.Select(x =&gt; x.Library)),然后是myDb.Books.Add(library2Books.Select(x =&gt; x.Book)),最后是myDb.Library2Books.Add(library2Books)
    • @YuriyN。不,这不起作用,您将获得至少 AddRange 而不是 Add 所需的转换
    • 当然,错了,我们需要使用AddRange,但我不能完全理解,为什么它不起作用。
    • @YuriyN。我认为 library2Books 的问题。它没有正确链接或映射到相关实体。这正是我试图用我的答案告诉你的。您能否转储您的实体添加/修改的实体的对象树。这是一个很好的方法,可以让我看到您的实体之间缺少什么或究竟是什么问题。
    • 看起来问题可能是尝试异步保存的问题,或者您使用某种顺序键的事实,如果您使用 GUID,您可能会侥幸逃脱异步保存AND 没有得到重复键错误
    猜你喜欢
    • 1970-01-01
    • 2020-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-09
    • 2021-04-09
    • 1970-01-01
    • 2022-12-10
    相关资源
    最近更新 更多