好的,所以我跟随了“多对多”对象。实体框架核心的示例: 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();
}
}
}
数据表:
我当然希望我做错了什么并且它不是一个错误..
答案 0 :(得分:3)
最新的EF不支持自动延迟加载。您可以阅读更多内容并跟踪此任务here.
EF团队表示,他们尚未决定自动延迟加载是否会包含在即将发布的更新中。 要回答您的问题,您需要手动加载关系数据。为此,您可能需要使用EF提供的Include
和ThenInlcude
方法。
示例:
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();
}