为什么未在.Include()上加载相关实体?

时间:2019-05-01 20:18:48

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

有人可以告诉我为什么相关的Article实体没有加载到.Include(a => a.Article)上吗?即使NULL确实具有值,它们也始终为ArticleIdFrontPageItemArticle之间的关系是1-0..1。 Article可以不与FrontPageItem有任何连接而存在,但是FrontPageItem必须有一个Article

在一个相当丑陋的解决方法中,我求助于foreach-遍历列表中的所有返回项,然后手动添加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);
}

1 个答案:

答案 0 :(得分:0)

首先,您需要了解急切加载,延迟加载,显式加载

  

急切加载

     

快速加载可帮助您一次加载所有需要的实体;   也就是说,您的所有子实体都将在单个数据库调用中加载。   这可以通过使用Include方法来实现,   相关实体作为查询的一部分,并且大量数据是   一次加载。

     

延迟加载

     

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

     

显式加载

     

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

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

我的示例代码如下

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

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