-1

I have a DbSet containing the class "Week". One of the properties in the class is a list containing a class "Day".

public class Week
{
    [Key]
    public int Id { get; set; }
    public List<Day> Days { get; set; }
    public bool Ferie { get; set; }
    public int WeekNo { get; set; }
    public int Year { get; set; }
}

public class Day
{
    [Key]
    public int Id { get; set; }
    public List<ProjectTask> Tasks { get; set; }
    public DateTime Date { get; set; }
    public int AvailableHours { get; set; }
    public int HoursLeftToBook { get; set; }
    public string? DayName { get; set; }
    public int Priority { get; set; }
}

The database is set up as follows, with migrations. I created a news migrations after changes, so the database should be up do date.

public class ApplicationDbContext : IdentityDbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
        Database.Migrate();
    }

    public DbSet<Week> Weeks { get; set; }
}

Currently, I'm testing out the database from the controller. First, I load the mockdata, save it to the database, and load the data from the database again, for display on the page.

    public IActionResult Index()
    {
        PlannerViewModel plannerViewModel = new();
        
        var mock = _plannerService.MockData();
        
        // Save to database
        _dataService.SaveWeeks(_plannerService.AssignProjects(mock));

        // Get from database
        plannerViewModel.Weeks = _dataService.GetWeeks();

        return View(plannerViewModel);
    }

The methods saving and returning the table, for reference:

    public void SaveWeeks(List<Week> weeks)
    {
        _db.Weeks.AddRange(weeks);
        _db.SaveChanges();
    }

    public List<Week> GetWeeks()
    {
        return _db.Weeks.ToList();
    }

The weeks display fine on the page when loaded, and contain the correct days. Afterwards I comment out the lines getting the mock data and saving it to the Database, since the mock data is then already added. Just the line "_dataService.GetWeeks();" is kept (and of course the viewModel code), and the project is rerun. The weeks are now still fetched from the database correctly, but suddenly the list of days in each week is null. I checked the database, and nothing has changed in between the two runs. Are the relationships wired incorrectly? And if so, why would it work the first time, and not the following?

4
  • Whag database are you using ? And how do you keep days in db? I can' t see any relations between a day and a week. Commented Dec 18, 2021 at 23:37
  • @Serge I'm using SQLite, since it's on MacOS. When the property on Week is of type Day, doesn't that create the relation? Day shouldn't know of Week, only the other way around. Commented Dec 18, 2021 at 23:39
  • And how you are going to save days? what column will keep the list of objects? Commented Dec 18, 2021 at 23:40
  • @Serge When looking at the DB, it creates a table for Days automatically, which then contains a column pointing to the Week ID. Commented Dec 18, 2021 at 23:42

1 Answer 1

3

It is probably because your method to fetch the data is not eager loading the related data with .Include. When you call data that adds entities to a DbContext, that DbContext will be tracking those newly added entities and any related entities added along with them. When you read the top level entities (weeks) from the DbContext, even though you don't eagerly load the child entities (days), since the DbContext is already tracking the Days, it will still populate those child relationships.

The second time around you are relying on the data already in the database. The DbContext isn't tracking these entities, so when you get dbContext.Weeks.ToList() you will just get the Weeks, without the associated days.

Whenever you expect related data when fetching an object graph, be sure to either:

A) Always eager load the related data:

var weeks = dbContext.Weeks.Include(w => w.Days).ToList();

B) Rely on projection to get the data you need where you don't need Entities:

var weekDetails = dbContext.Weeks
    .Select(w => new WeekDetailViewModel
    {
        Id = w.Id,
        WeekNo = w.WeekNo,
        Days = w.Days.Select(d => new DayDetailViewModel
        {
            Id = d.Id,
            // ...
        }).ToList()
    }).ToList();
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.