I have an application in ASP.NET 6 that uses Entity Framework core as ORM. Just as a side-note I don't have a lot of experience with ORMs.
I have the following entities:
ApplicationUser:
public class ApplicationUser : IdentityUser
{
public string FullName { get; set; } = string.Empty;
public bool IsProfessional { get; set; } = false;
public ICollection<Address>? Addresses { get; set; } = default;
}
A user can have several addresses, hence the ICollection property.
Address:
public class Address
{
public string Id { get; set; } = string.Empty;
public string UserId { get; set; } = string.Empty;
public ApplicationUser User { get; set; } = default;
public string Street { get; set; } = string.Empty;
public string Number { get; set; } = string.Empty;
public string Neighborhood { get; set; } = string.Empty;
public string ZipCode { get; set; } = string.Empty;
public string CityId { get; set; } = string.Empty;
public City City { get; set; } = default;
}
The Address user contains the UserId of the user, and a User property for navigation purposes. It also contains a CityId, and a City property also for navigation purposes.
City:
public class City
{
public string Id { get; set; }
public string Name { get; set; } = string.Empty;
public State State { get; set; } = default;
public ICollection<Address>? Addresses { get; set; } = default;
}
A city belogs to several addresses, so here I have the collection Addresses for navigation purposes.
I'm using Identity Framework to manage my users. And at some point within my code I need to load the user (using the UserManager) and the user related properties, such as address, and related to address, the city.
Here's the snippet where I'm having issues:
public async Task<GetUserQueryResponse> Handle(GetUserQuery request, CancellationToken cancellationToken)
{
var user = await _userManager.Users
// Here I include the Addresss and hope that the City property is loaded
// for each address
.Include(u => u.Addresses)
.Where(u => u.Id == request.UserId).FirstOrDefaultAsync();
var userAddresses = new List<GetAddressForUserDTO>();
foreach (var address in user.Addresses)
{
userAddresses.Add(new GetAddressForUserDTO()
{
Id = address.Id,
UserId = address.Id,
Street = address.Street,
Number = address.Number,
Neighborhood = address.Neighborhood,
ZipCode = address.ZipCode,
City = address.City.Name, // PROBLEM: The city is null, was not loaded.
State = address.City.State.Abbreviation // PROBLEM: The city is null.
});
}
// rest of the code
}
Here's the output when debugging:
Is there a way I can write this query or change the entities to allow the framework to load the related properties when writing queries such as this one? What am I doing wrong?
You need to also include the City
navigation property:
var user = await _userManager.Users
.Include(u => u.Addresses)
// loading the address, also get the City
.ThenInclude(a => a.City)
.Where(u => u.Id == request.UserId)
.FirstOrDefaultAsync();