Home > OS >  C# ASP.NET Entity Framework - T successfully saves to Db, but does not appear in User's List<
C# ASP.NET Entity Framework - T successfully saves to Db, but does not appear in User's List<

Time:01-02

I have an ApplicationUser, that has a collection of UserAddress. I simply want to expose endpoints to perform CRUD on these addresses. However when I successfully create an Address (A new row appears in the table, and the User's list of addresses go up by one), when I then go to call another endpoint, the Addresses have reset to 0.

My ApplicationUser model looks like

public class ApplicationUser : IdentityUser
{
    // other stuff..

    public virtual ICollection<UserAddress> UserAddresses { get; set; } = new List<UserAddress>();
}

My UserAddress model

public class UserAddress
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    [Key]
    public Guid Id { get; set; }

    // Stuff

    public string ApplicationUserId { get; set; }

    public virtual ApplicationUser ApplicationUser { get; set; } = null!;
}

There's no Fluent Api stuff in my DbContext (although I have spent a long time trying some solutions), but I have a public DbSet<UserAddress> UserAddresses { get; set; }

My endpoint for adding an address for a user is simply

    [HttpPost("Create")]
    public async Task<IActionResult> CreateAddress([FromBody] UserAddressDTO request)
    {
        var user = await _userManager.GetUserAsync(User);
        if (user is null)
        {
            return Unauthorized(new ApiError("Could not get a user"));
        }

        var mappedAddress = new UserAddress
        {
            Line1 = request.Line1,
            Line2 = request.Line2,
            City = request.City,
            Country = request.Country,
            Postcode = request.Postcode,
            IsPrimaryAddress = request.IsPrimaryAddress,
            // I don't usually do this, this probably is not necessary but I've been trying a lot of things
            ApplicationUser = user,
            ApplicationUserId = user.Id,
        };

        user.UserAddresses.Add(mappedAddress);
        await _context.SaveChangesAsync();

        // Inspector says user.UserAddresses has a count of 1 at this point. A row is created with the UserId.

        return Ok();
    }

And then when I GET it, it's empty.

    [HttpGet("All")]
    public async Task<IActionResult> GetAll()
    {
        var user = await _userManager.GetUserAsync(User);
        if (user is null)
        {
            return Unauthorized(new ApiError("Could not get a user"));
        }

        // Empty array.
        var addressesForUser = user.UserAddresses;

        return Ok(addressesForUser);
    }

Believe me I have read 999 stack overflow posts, I've read my .NET book, Microsoft docs lol. I am going mad. Usually when I'd do a task like this I'd create the new entity (without any references to what has a collection of it), create a new collection of that entity in the class I want it in, and EF would do some magic and it would just work.

Edit: Added the addresses to the Ok in the GET, I was fiddling with the code, I wouldn't normally return the model objects.

CodePudding user response:

Your forgetting to include the UserAddress, that's why the Address are null

var addressesForUser = user.include(e => e.user.UserAddresses);

I believe your call should be var addressesForUser = applicationuser.include(e => e.applicationuser.UserAddresses);

If you're not using autoInclude. As i can't see you including the List of object. asp.net.core does not autoinclude when calling a List of object inside a class. IT has been recently created in EF6 where they implemented AutoInclude in the ModelBuilder

CodePudding user response:

Thank you to RojhatSefdin for giving me the insight to fix this problem. The code that solved it for me is

    [HttpGet("All")]
    public IActionResult GetAll()
    {
        var userId = _userManager.GetUserId(User);
        var user = _context.Users
            .Include(e => e.UserAddresses)
            .FirstOrDefault(x => x.Id == userId);

        if (user is null)
        {
            return Unauthorized(new ApiError("Could not get a user"));
        }

        return Ok(_mapper.Map<IList<UserAddressDTO>>(user.UserAddresses));
    }

I'm not 100% sure yet but I believe the User I was getting from the UserManager did not include all the other attributes (lazy loading?), so I changed it to just fetch the Id, then I queried the DB with the .Include() to get what I needed.

  • Related