实体框架核心多对多关系不从数据库加载

时间:2017-05-03 08:31:37

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

好的,所以我跟随了“多对多”对象。实体框架核心的示例: Relationships(在页面末尾)。

似乎在最初创建数据库时(createNew设置为true),一切都按预期工作,但是当我使用现有数据库(createNew设置为false)时,连接不再存在。以下是一个控制台应用程序,显示我遇到的问题:

createNew = true的输出:

作者1写道: - 第1册 - 第2册

作者2写道: - 第1册 - 第2册

作者3写道: - 第4册

Auhtor 4写道:  还没有书

createNew = false的输出:

作者1写道:  还没有书

作者2写道:  还没有书

作者3写道:  还没有书

Auhtor 4写道:  还没有书

// Visual Studio 2017
// Console App (.NET Core)
// Nuget: Microsoft.EntityFrameworkCore.SqlServer

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;

namespace ConsoleAppCoreEFMany
{
    /* 
    An Author can write several Books, and a Book can be written by several Authors..
    https://en.wikipedia.org/wiki/Many-to-many_(data_model)
    */

    class Author
    {
        public long AuthorId { get; set; }
        public string Name { get; set; }

        public List<AuthorBook> AuthorBook { get; set; }        
    }

    class Book
    {
        public long BookId { get; set; }
        public string Title { get; set; }

        public List<AuthorBook> AuthorBook { get; set; }
    }   

    class AuthorBook
    {
        public long AuthorId { get; set; }
        public Author Author { get; set; }

        public long BookId { get; set; }
        public Book Book { get; set; }
    }  

    class MyDbContext : DbContext
    {        
        public DbSet<Author> Author { get; set; }
        public DbSet<Book> Book { get; set; }        
        public DbSet<AuthorBook> AuthorBook { get; set; }        

        string connectionString = "";

        public MyDbContext(string connectionString, bool createNew)
        {
            this.connectionString = connectionString;

            if (createNew)
            {
                Database.EnsureDeleted();
                Database.EnsureCreated();
            }

            // to see the actual tables created add a Data Connection in View / Server Explorer, Data Source: (Microsoft SQL Server Database File), Browse: C:/Users/<user>/*.mdf (in this case TestEFManyMany.mdf)
        }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer(connectionString);
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<AuthorBook>()
                .HasKey(x => new { x.AuthorId, x.BookId }); // creates a composite key

            modelBuilder.Entity<AuthorBook>()
                .HasOne(x => x.Author)
                .WithMany(x => x.AuthorBook)
                .HasForeignKey(x => x.AuthorId);

            modelBuilder.Entity<AuthorBook>()
                .HasOne(x => x.Book)
                .WithMany(x => x.AuthorBook)
                .HasForeignKey(x => x.BookId);           
        }
    }

    class Program
    {


        static void Main(string[] args)
        {
            bool createNew = false;

            using (var db = new MyDbContext("Server=(localdb)\\mssqllocaldb;Database=TestEFManyMany;Trusted_Connection=True;MultipleActiveResultSets=True", createNew))
            {
                try
                {
                    if (createNew)
                    {
                        // creating some 'unlinked' books
                        var book1 = new Book { Title = "Book 1" };
                        var book2 = new Book { Title = "Book 2" };
                        var book3 = new Book { Title = "Book 3" };

                        db.Book.Add(book1);
                        db.Book.Add(book2);
                        db.Book.Add(book3);
                        db.SaveChanges();

                        // creating some 'unlinked' authors
                        var author1 = new Author { Name = "Author 1" };
                        var author2 = new Author { Name = "Author 2" };

                        db.Author.Add(author1);
                        db.Author.Add(author2);
                        db.SaveChanges();

                        // link authors and books

                        // Author 1 and Author 2 have written Book 1
                        db.AuthorBook.Add(new AuthorBook { AuthorId = author1.AuthorId, BookId = book1.BookId });
                        db.AuthorBook.Add(new AuthorBook { AuthorId = author2.AuthorId, BookId = book1.BookId });

                        db.SaveChanges();

                        // Author 2 also has written Book 2
                        db.AuthorBook.Add(new AuthorBook { AuthorId = author2.AuthorId, BookId = book2.BookId });

                        // creating initially linked 
                        db.AuthorBook.Add(new AuthorBook
                        {
                            Author = new Author { Name = "Author 3" },
                            Book = new Book { Title = "Book 4" }
                        });

                        db.SaveChanges();

                        // check if link between author 2 and book 1 exists
                        if (db.AuthorBook.Where(x => x.AuthorId == author2.AuthorId && x.BookId == book1.BookId).Count() == 0)
                        {
                            db.AuthorBook.Add(new AuthorBook { AuthorId = author2.AuthorId, BookId = book1.BookId });
                        }

                        // check if link between author 1 and book 2 exists
                        if (db.AuthorBook.Where(x => x.AuthorId == author1.AuthorId && x.BookId == book2.BookId).Count() == 0)
                        {
                            db.AuthorBook.Add(new AuthorBook { AuthorId = author1.AuthorId, BookId = book2.BookId });
                        }

                        db.SaveChanges();

                        var author4 = new Author { Name = "Auhtor 4" };
                        db.Author.Add(author4);
                        db.SaveChanges();                       
                    }


                    foreach (var author in db.Author)
                    {
                        Console.WriteLine(author.Name + " has written:");

                        if (author.AuthorBook != null)
                        {
                            var books = author.AuthorBook.Select(x => x.Book).ToList();

                            foreach (var book in books)
                            {
                                Console.WriteLine("- " + book.Title);
                            }                            
                        }
                        else
                        {
                            Console.WriteLine(" no books yet");
                        }

                        Console.WriteLine();
                    }                   
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Exception: " + ex.Message);
                }                
            }

            Console.ReadKey();
        }
    }
}

数据表:

enter image description here

我当然希望我做错了什么并且它不是一个错误..

2 个答案:

答案 0 :(得分:3)

最新的EF不支持自动延迟加载。您可以阅读更多内容并跟踪此任务here.

EF团队表示,他们尚未决定自动延迟加载是否会包含在即将发布的更新中。

要回答您的问题,您需要手动加载关系数据。为此,您可能需要使用EF提供的IncludeThenInlcude方法。

示例:

 ctx.EntityOne
    .Include(eOne => eOne.EntityTwo)
    .ThenInclude(eTwo => eTwo.SomeOtherEntity)
    .Where(entityOne => YourQuery);

此代码剪切将加载这些实体之间的关系链接,就像在以前的EF版本中自动完成一样。

答案 1 :(得分:0)

好的Ivan Stoev指出我正确的方向: Loading Related Data

根据提示加载:

实体框架核心会自动将导航属性修复到先前加载到上下文实例中的任何其他实体。因此,即使您没有明确包含导航属性的数据,如果之前加载了部分或全部相关实体,仍可能会填充该属性。

因此将 var eagerLoading = db.AuthorBook.Include(x =&gt; x.Author).Include(x =&gt; x.Book).ToList(); 放入其中就足够了在上下文中循环的前面(注意你必须使用连接表才能包括Author和Book,还有ToList()是必要的)

var eagerLoading = db.AuthorBook.Include(x => x.Author).Include(x => x.Book).ToList();

foreach (var author in db.Author)
{
    Console.WriteLine(author.Name + " has written:");

    if (author.AuthorBook != null)
    {
        var books = author.AuthorBook.Select(x => x.Book).ToList();

        foreach (var book in books)
        {
            Console.WriteLine("- " + book.Title);
        }
    }
    else
    {
        Console.WriteLine(" no books yet");
    }

    Console.WriteLine();
}