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.
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.
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