【问题标题】:Loading list of data which references related data in another table加载引用另一个表中相关数据的数据列表
【发布时间】:2020-01-24 12:06:19
【问题描述】:

已解决

我试图弄清楚如何从实体框架中的表中检索相关数据的集合,但我还没有解决它。

两个表之间是多对多的关系,如下图所示:

我的问题是我想将相关的 BOOK 检索给 Author,它是 BOOK 表的 ICollection,但是当我返回时它给了我一个空列表。 我尝试使用显式加载来解决这个问题:

public AUTHOR Read(int Aid)
{
    using(var db = new LibraryDBEntities1())
    {
        var author = db.AUTHORs.Find(Aid);
        db.Entry(author).Collection(a => a.BOOKs).Load();

        return author;
    }
}

我也尝试过使用急切加载来解决它

return db.AUTHORs.Where(a => a.Aid == Aid).Include("BOOKs").FirstOrDefault();

但它也没有工作。我试图按照 microsoft docs Loading Related Entities 上的文档进行操作,但我无法弄清楚我做错了什么。 有人可以帮我解决这个问题,也许可以解释我哪里做错了吗?

编辑 1 这就是 OnModelCreating 的样子。我应该在这里更改/添加代码吗?我一直在使用数据库优先的方法。


protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    throw new UnintentionalCodeFirstException();
}

编辑 2

数据库连接应如下所示:

编辑 3

我忘了提到我正在使用 3 层架构,包括表示层 (MVC)、业务逻辑层和数据访问层。还有一个包含数据库的数据层,如下图所示。

解决方案

所以我终于解决了!所以问题并不是我最初认为的问题,而是我如何使用 Mapper 的问题。 我必须在我的模型中添加以下代码才能使其工作:

authorObj.BooksList = Mapper.Map<List<BOOK>, List<Book>>(aauthor.BOOKs.ToList());

现在它可以正常工作了!

【问题讨论】:

  • 你是如何在你的 c# 模型中定义多对多关系的(你能从你的上下文文件的 OnModelCreating 中发布 sn-p
  • @sam 感谢您的评论!我是实体框架的新手,所以我不知道我应该更改上下文文件中的任何内容。我已经编辑了问题并在 OnModelCreating 上添加了一个 sn-p
  • 您使用的是哪个 EF 版本?
  • @ilkerkaran 我使用的是 EF 版本 6.4.0
  • @JulijusErgül 你不想做任何事情。我觉得你的..Include("BOOKs") 有问题,你可以试试Include(a =&gt; a.Books) 吗?

标签: c# asp.net-mvc entity-framework


【解决方案1】:

EF 6 包含多对多关系的默认约定。您需要在两端包含一个集合导航属性。所以你的模型类定义绝对没问题。你应该做的是更新OnMOdalCreating,如下所示;

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);
}

然后你可以像下面这样使用它;

return db.AUTHORs.Where(a => a.Aid == Aid).Include(a => a.BOOKs).FirstOrDefault();

P.S:我强烈建议你为 junction 类型创建一个模型类。

编辑 使用数据库优先方法,您基本上必须为数据库中的每个表创建一个模型类。

所以不要改变你的OnMOdalCreating 方法。添加一个新的类,如下所示;

[Table("BOOK_AUTHOR")]
public class BookAuthor
{
    public int ISBN { get; set; }
    public int AId { get; set; }
    public virtual Book Book { get; set; }
    public virtual Author Author { get; set; }
}

那么您需要通过属性或 Fluent API 将属性绑定到主键属性。之后,您将能够获得具有以下书籍的作者

var authorWithBooks = context.Authors
    .Include(a => a.BookAuthors.Select(ba => ba.Book))
    .Where(...)
    .ToList();

【讨论】:

  • 感谢您的回答!我试过了,但没有用。你认为我应该先迁移到代码优先而不是数据库优先,然后为联结表创建一个模型类,还是我现在可以使用我正在采用的方法添加它?
  • 迁移到 Code-First 取决于项目的需要。但无论哪种方式,我都会为连接添加一个模型。我认为它提供了更大的灵活性
  • @ilkerkaran 据我所知,如果联结表除了两个表的主键之外没有任何其他列。因此,在这种情况下,由于 OP 没有其他列,因此不需要显式模型(公共类 BookAuthor...)。
  • 我应该在哪个班级添加var authorWithBooks = context.Authors .Include(a =&gt; a.BookAuthors.Select(ba =&gt; ba.Book)) .Where(...) .ToList();
  • 如何将属性绑定到主键?
【解决方案2】:

由于它的数据库优先方法,请尝试将以下映射添加到您的 OnModelCreating 函数

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
     base.OnModelCreating(modelBuilder);

     modelBuilder.Entity<BOOKs>()
        .HasMany<AUTHORs>(b => b.AUTHORs)
        .WithMany(a => a.BOOKs)
        .Map(m => m.ToTable("BOOK_AUTHOR")
        .MapLeftKey("ISBN")
        .MapRightKey("Aid"));

// or like below
       /* modelBuilder.Entity<BOOKs>()
         .HasMany<AUTHORs>(s => s.AUTHORs)
         .WithMany(c => c.BOOKs)
         .Map(cs =>
         {
              cs.MapLeftKey("ISBN");
              cs.MapRightKey("Aid");
              cs.ToTable("BOOK_AUTHOR"); // Use the correct junction table name here. and correct key names
         });*/
    }

另外,删除抛出异常的语句。

然后使用:

db.AUTHORs.Include("BOOKs").Where(a => a.Aid == Aid).FirstOrDefault();

db.AUTHORs.Include(a => a.BOOKs).Where(a => a.Aid == Aid).FirstOrDefault();

或者简单地说,直接在 FirstOrDefault 中使用谓词而不使用 WHERE 子句。

db.AUTHORs.Include(a => a.BOOKs).FirstOrDefault(a => a.Aid == Aid); // Same as above two queries.

更新

var query = db.AUTHORs.Include(a => a.BOOKs).Where(a => a.Aid == Aid);
var firstBook = query.FirstOrDefault(); // Have a break point here. Please see what is in query via quick watch.

在quick watch for query(不是firstBook)中,你应该看到如下所示的Sql:

请在直接在 SSMS 中执行后,使用该 SQL 语句并在此处发布您的观察结果,例如

  • 您是否在查询中看到与 BOOKs 的联接
  • 结果集是否包含 BOOK 中的列。

【讨论】:

  • 感谢您的回答!我也尝试过这样做,但结果还是一样。
  • 另外,你能说出 LazyLoadingEnabled 和 ProxyCreationEnabled 是真还是假吗?或发布您的上下文的构造函数
  • 我在查询error CS0103: The name 'query' does not exist in the current context时从快速观看得到以下回复
  • hmm...您是否将变量命名为查询?你能把代码贴出来吗?
  • 这是我写的代码var query = db.AUTHORs.Include(a =&gt; a.BOOKs).Where(a =&gt; a.Aid == Aid); var firstBook = query.FirstOrDefault();
猜你喜欢
  • 2010-11-22
  • 1970-01-01
  • 1970-01-01
  • 2021-08-31
  • 2021-10-17
  • 1970-01-01
  • 2019-02-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多