【问题标题】:Why aren't related entities loaded on .Include()?为什么 .Include() 上没有加载相关实体?
【发布时间】:2019-05-01 20:18:47
【问题描述】:

谁能告诉我为什么相关的Article 实体没有被加载到.Include(a => a.Article) 上?它们总是NULL,即使ArticleId 确实有价值。 FrontPageItemArticle 之间的关系是 1-0..1。 Article 可以在没有任何连接到 FrontPageItem 的情况下存在,但 FrontPageItem 必须有一个 Article

在一个相当丑陋的解决方法中,我使用foreach-ing 遍历列表中的所有返回项目并手动添加Article,正如您在下面的索引方法中看到的那样。

public async Task<IActionResult> Index()
{
    List<FrontPageItem> items = await db.FrontPageItems
        .Include(a => a.Article)
            .ThenInclude(c => c.CreatedBy)
                .ThenInclude(m => m.Member)
        .Include(a => a.Article)
            .ThenInclude(e => e.EditedBy)
                .ThenInclude(m => m.Member)
        .Include(a => a.Article)
            .ThenInclude(e => e.PublishReadyBy)
                .ThenInclude(m => m.Member)
        .Include(p => p.WebPage)
        .OrderByDescending(o => o.DatePublished)
        .ToListAsync();
    // I don't want to foreach, but without it, Article is always NULL for all items.
    foreach (FrontPageItem item in items)
    {
        item.Article = await db.Articles
            .Where(a => a.Id == item.ArticleId).FirstOrDefaultAsync();
    }
    List<FrontPageItemViewModel> vm = 
        auto.Map<List<FrontPageItemViewModel>>(items);
    return View(vm);
}

这些是模型:

public class FrontPageItem
{
    public int Id { get; set; }
    // ... some more properties
    public int? ArticleId { get; set; }
    public Article Article { get; set; }

    public AdminUser CreatedBy { get; set; }
    public AdminUser EditedBy { get; set; }
    public AdminUser PublishedBy { get; set; }

}

public class Article
{
    public int Id { get; set; }
    // ... some more properties
    public int? FrontPageItemId { get; set; }
    public FrontPageItem FrontPageItem { get; set; }

    public AdminUser CreatedBy { get; set; }
    public AdminUser EditedBy { get; set; }
    public AdminUser PublishReadyBy { get; set; }
}

public class AdminUser
{
    public int Id { get; set; }
    // ... some more properties
    public int MemberId { get; set; }
    public Member Member { get; set; }
}

public class Member
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    // ... some more properties
    public AdminUser AdminUser { get; set; }
}

这是模型构建器:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Article>()
        .HasOne(p => p.FrontPageItem)
        .WithOne(i => i.Article)
        .HasForeignKey<Article>(b => b.FrontPageItemId);
}

【问题讨论】:

  • 如果你尝试这个 `var items = await db.FrontPageItems.Include(a => a.Article).ToListAsync();` 你有空值吗?
  • @hassan.ef 是的。还是null.
  • 您的实体模型出了点问题,尤其是当您对previous question 使用公认的错误 答案时。关系仅包括 1 个 FK,因此 FrontPageItem 中的 ArticleIdArticle 中的 FrontPageItemId 都是多余的。很可能是第二个。所以保留第一个,删除第二个并使用.HasForeignKey&lt;FrontPageItem&gt;(b =&gt; b.ArticleId)。与链接问题的其他关系类似。
  • @IvanStoev 是的!你可以把它写下来作为答案,我会接受的。

标签: c# linq asp.net-core entity-framework-core


【解决方案1】:

首先你需要了解急切加载、延迟加载、显式加载

预加载

Eager Loading 可帮助您一次加载所有需要的实体; 即,您的所有子实体都将在单个数据库调用中加载。 这可以使用 Include 方法来实现,该方法返回 相关实体作为查询的一部分和大量数据是 一次加载。

延迟加载

这是实体框架的默认行为,其中一个子 实体仅在第一次访问时才加载。它 只是延迟加载相关数据,直到您提出要求。

显式加载

在实体框架中有禁用延迟加载的选项。 关闭延迟加载后,您仍然可以通过以下方式加载实体 显式调用相关实体的 Load 方法。有 两种使用Load方法的方法参考(加载单个导航 属性)和集合(加载集合)

所以要加载关系实体,您可以使用 Microsoft.EntityFrameworkCore.Proxies 包来启用延迟加载。因此,当您查询数据库时,EF 将根据它们的关系返回关系数据库

我的示例代码是这样的

services.AddDbContextPool<ApplicationDbContext>(options =>
  options.UseLazyLoadingProxies().UseSqlServer(configuration.GetConnectionString("DefaultConnection"),
        b => b.MigrationsAssembly("AwesomeCMSCore")).UseOpenIddict());

如果您有任何问题,请告诉我

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多