EF Core's Include() function not working from direct GET request

asp.net-core blazor c# entity-framework-core sql-server

Question

I am building this app using.NET Core 3.1 and my json output isn't right. Here is the class I want a list of:

[DataContract(IsReference = true)]
public class State
{
    public int Id { get; set; }

    [DataMember]
    public string Name { get; set; }

    [DataMember]
    public List<Region> Regions { get; }

    public State()
    {
        Name = string.Empty;
        Regions = new List<Region>();
    }

    public State(string name)
    {
        Name = name;
        Regions = new List<Region>();
    }
}

It has a list of Regions and that class goes as follows:

[DataContract(IsReference = true)]
public class Region
{
    public int Id { get; set; }

    [DataMember]
    public string Name { get; set; }

    [DataMember]
    public List<County> Counties { get; }

    [DataMember]
    public List<Report> Reports { get; }

    [DataMember]
    public State State { get; set; }
    public int StateId { get; set; }

    public Region()
    {
        Name = string.Empty;
        State = new State();
        Reports = new List<Report>();
        Counties = new List<County>();
    }

    public Region(string name)
    {
        Name = name;
        State = new State();
        Reports = new List<Report>();
        Counties = new List<County>();
    }
}

This is my method:

[HttpGet]
public async Task<ActionResult<List<State>>> GetReportsAsync()
{
    return await context.States.Include(x => x.Regions).ToListAsync() is IList<State> states
        ? Ok(states)
        : (ActionResult<List<State>>)NoContent();
}

This is my DbContext:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    if (modelBuilder is null) throw new ArgumentNullException(nameof(modelBuilder));
    modelBuilder.Entity<Report>(report =>
    {
        report.HasOne(x => x.County).WithMany(x => x.Reports).HasForeignKey(x => x.CountyId);
        report.HasOne(x => x.Region).WithMany(x => x.Reports).HasForeignKey(x => x.RegionId);
    });

    modelBuilder.Entity<State>(state => state.HasIndex(x => x.Name).IsUnique());

    modelBuilder.Entity<Region>(region =>
    {
        region.HasIndex(x => x.Name).IsUnique();
        region.HasOne(x => x.State).WithMany(x => x.Regions).HasForeignKey(x => x.StateId);
    });

    modelBuilder.Entity<County>(county =>
    {
        county.HasIndex(x => x.Name).IsUnique();
        county.HasOne(x => x.Region).WithMany(x => x.Counties).HasForeignKey(x => x.RegionId);
    });
}

And yet I don't get my Regions list populated in the json output. I should point out that I do get the expected result after I call another method which populates the database and then calls this one, but if I do a direct call my Reports list will be empty. Please help me out here.

1
0
4/2/2020 2:31:04 AM

Accepted Answer

The problem is caused by the reference navigation property initializer:

public Workplace Workplace { get; set; } = new Workplace(); // <--

Never do that - it confuses EF navigation property fixup and leads to unexpected runtime behaviors.

Note that initializing collection navigation properties is ok, although not required. It's because null in reference navigation property have a special meaning and really provides a link to the principal entity, which may or may not contain collection of dependent entities.

Shortly, remove the initializer

public Workplace Workplace { get; set; }

and the issue will be solved.

2
3/2/2020 12:58:22 PM

Popular Answer

If you are using lazy loading of the data you need to enumerate the data in order for them to be pulled into the EF context. Child elements are not retrieved by default. Another thing you can do is explicitly include the children when constructing the query. You can see how the include operation works here: https://entityframework.net/include-multiple-levels

And you can also see the related issue here: Include children in EF



Related Questions





Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow