Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Child Model List is Empty after DB Add in Entity Framework Core

So I am trying out Entity Framework Core, and am having trouble with my first pair of relational Models. I'm trying to use conventions to form the relationship, as follows:

The principal entity, with conventional principal key (Id) and collection navigation property (the list of Locations):

public class Site
{
    public int Id { get; set; }
    public string Name { get; set; } = string.Empty;
    public int LocationCount { get; set; } = 1;
    public List<Location> Locations { get; set; } = new List<Location>();
}

The dependent entity, with conventional foreign key (SiteId) and reference navigation property (Site):

public class Location
{
    public int Id { get; set; }
    public int SiteId { get; set; }
    public Site Site { get; set; }
    public int AreaCount { get; set; } = 1;
    public Location(Site site) { SiteId = site.Id; }
}

And since I want every Site to already have at least one location, I put this in the Create action of the SiteController, in an attempt to create the dependents along with the principal:

[HttpPost]
public IActionResult Create(Site site)
{
    _context.Sites.Add(site);
    for (int i = 0; i < site.LocationCount; i++)
        _context.Locations.Add(new Location(site));
    _context.SaveChanges();
    return RedirectToAction("Details", new { Name = site.Name });
}

However, on the Details view, when I try to display the Locations that were created, the list is always empty:

<h2>@Model.Locations.Count Locations</h2>    
@foreach (Location l in Model.Locations)
{
    <div class="row">
        <div class="col-sm-12">@l.Id</div>
    </div>
}

Just results in:

0 Locations

Thank you in advance for any help explaining what I've missed!

Edit: By request, here is the body of the Details action in the Site Controller, which gets the Model data for the Details View:

public IActionResult Details(string name)
{
    var model = _context.Sites.FirstOrDefault(a => a.Name == name);
    if (model == null) model = new Site();
    return View(model);
}

Also, per one suggestion, I have fixed the problem of setting the Location.SiteId before Site.Id has a value, since the Id isn't automatically generated on the Site until after SaveChanges() is called. Unfortunately, the result (empty Locations list) is still the same:

[HttpPost]
public IActionResult Create(Site site)
{
    int nextsiteid = _context.Sites.Count() + 1;
    _context.Sites.Add(site);
    for (int i = 0; i < site.LocationCount; i++)
        _context.Locations.Add(new Location(siteid));
    _context.SaveChanges();
    return RedirectToAction("Details", new { Name = site.Name });
}

And changed the Location constructor to use the Id instead of the instance:

public Location(int siteid) { SiteId = siteid; }

Thanks in advance for any further suggestions!

like image 309
Jason Avatar asked Jan 31 '26 21:01

Jason


1 Answers

I'm just transcribing the answer I was given, which was provided in the comments of the original post, so that it can easily be found by anyone reading the post.

The issue was, quite simply, that EF Core does not yet support lazy loading. So when the Site entity is populated, it doesn't lazily load the list of dependent locations into the collection navigation property.

The fix is to use eager loading, by way of:

var model = _context.Sites.Include(s => s.Locations).FirstOrDefault(a => a.Name == name);

When loading the Model data of the Site to provide to the View.

Thanks for the solution, Ivan!

like image 157
Jason Avatar answered Feb 03 '26 10:02

Jason



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!