0

Can anybody tell me why the related Article entities are not being loaded on .Include(a => a.Article)? They are always NULL even though ArticleId does indeed have a value. The relationship between FrontPageItem and Article is 1-0..1. An Article can exist without any connection to a FrontPageItem, but a FrontPageItem must have one Article.

In a rather ugly workaround, I have resorted to foreach-ing through all the returned items in the list and adding Article manually, as you can see in my index-method below.

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);
}

These are the models:

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; }
}

This is the model-builder:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Article>()
        .HasOne(p => p.FrontPageItem)
        .WithOne(i => i.Article)
        .HasForeignKey<Article>(b => b.FrontPageItemId);
}
Stian
  • 1,522
  • 2
  • 22
  • 52
  • If you try this one ` var items = await db.FrontPageItems.Include(a => a.Article).ToListAsync();` again you have null value? – hassan.ef May 01 '19 at 20:33
  • @hassan.ef Yes. Still `null`. – Stian May 01 '19 at 20:37
  • 1
    Something is wrong with your entity model, especially if you are using the accepted *wrong* answer to your [previous question](https://stackoverflow.com/questions/55889449/how-to-configure-this-one-to-zero-or-one-relationship). Relationships include only 1 FK, so either `ArticleId` in `FrontPageItem` or `FrontPageItemId` in `Article` is redundant. Most likely the second. So keep the first, remove the second and use `.HasForeignKey(b => b.ArticleId)`. Similar for the other relationship from the linked question. – Ivan Stoev May 01 '19 at 21:51
  • @IvanStoev Yes! You can write that up as an answer, and I will accept it. – Stian May 02 '19 at 07:42

1 Answers1

0

First you need to understand about Eager Loading, Lazy Loading, Explicit loading

Eager Loading

Eager Loading helps you to load all your needed entities at once; i.e., all your child entities will be loaded at single database call. This can be achieved, using the Include method, which returs the related entities as a part of the query and a large amount of data is loaded at once.

Lazy Loading

It is the default behavior of an Entity Framework, where a child entity is loaded only when it is accessed for the first time. It simply delays the loading of the related data, until you ask for it.

Explicit Loading

There are options to disable Lazy Loading in an Entity Framework. After turning Lazy Loading off, you can still load the entities by explicitly calling the Load method for the related entities. There are two ways to use Load method Reference (to load single navigation property) and Collection (to load collections)

So to load relational entity you can use Microsoft.EntityFrameworkCore.Proxies package to enable lazy loading. So when you query database EF will return relational data base on their relationship

My sample code is look like this

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

Please let me know if you have any problem