Entity Framework many-to-many relationship in a html table

Viewed 138

I am creating an ASP.NET project in .net core 3.1 that contains 2 tables (User and Address) with NxN relation through a third table (UserAddress)

public class User
{
    public Guid ID { get; set; }
    [Required]
    public string Name { get; set; }
    public int Age { get; set; }
    public string Email { get; set; }
    public string Description { get; set; }
    public List<UserAddress> Addresses { get; set; }
}

public class Address
{
    public Guid ID { get; set; }
    [Required]
    public string Information { get; set; }
    public bool IsCommercial { get; set; }
    public List<UserAddress> Users { get; set; }
}

public class UserAddress
{
    public Guid UserID { get; set; }
    public Guid AddressID { get; set; }
    public User User { get; set; }
    public Address Address { get; set; }
}

public class ManagerContext : DbContext
{
    public ManagerContext(DbContextOptions<ManagerContext> options) : base(options)
    {
    }

    public DbSet<User> User { get; set; }
    public DbSet<Address> Address { get; set; }
    public DbSet<UserAddress> UserAddress { get; set; }
    public DbSet<Department> Department { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<User>()
            .HasIndex(e => new { e.Name })
            .IsUnique(true);

        modelBuilder.Entity<Address>()
            .HasIndex(e => new { e.Information })
            .IsUnique(true);

        modelBuilder.Entity<UserAddress>()
            .HasKey(e => new { e.UserID, e.AddressID });

        modelBuilder.Entity<Department>()
            .HasIndex(e => new { e.Name })
            .IsUnique(true);
    }
}

I want to create an HTML page that shows details for a specific user and a list of addresses related to the user

<div>
    <h4>User</h4>
    <hr />
    <dl class="row">
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Name)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Name)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Age)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Age)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Email)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Email)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Description)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Description)
        </dd>
    </dl>

    <table class="table table-striped">
        <thead>
            <tr>
                <th scope="col">#</th>
                <th scope="col">@Html.DisplayNameFor(model => model.Addresses[0].Address.Information)</th>
                <th scope="col">@Html.DisplayNameFor(model => model.Addresses[0].Address.IsCommercial)</th>
            </tr>
        </thead>
        <tbody>
            @for (int i = 0; i < Model.Addresses.Count; i++)
            {
                <tr>
                    <th scope="col">@i</th>
                    <td>@Html.DisplayFor(model => model.Addresses[i].Address.Information)</td>
                    <td>@Html.DisplayFor(model => model.Addresses[i].Address.IsCommercial)</td>
                </tr>
            }
        </tbody>
    </table>
</div>

However, for some reason, the User.Addresses list is null and returns an error since the code tries to get the Count property of a null object. Why was the list not populated with the UserAddress list? What am I doing wrong?

1 Answers

public class User
{
    public Guid ID { get; set; }
    [Required]
    public string Name { get; set; }
    public int Age { get; set; }
    public string Email { get; set; }
    public string Description { get; set; }
    public List<Address> Addresses { get; set; }
}

public class Address
{
    public Guid ID { get; set; }
    [Required]
    public string Information { get; set; }
    public bool IsCommercial { get; set; }
    public List<User> Users { get; set; }
}

public class UserAddress
{
    public Guid ID { get; set; }
    public Guid UserId { get; set; }
    public Guid AddressId { get; set; }
    public DateTime CreatedAt { get; set; }
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    modelBuilder.Entity<User>()
        .HasMany(user => user.Addresses)
        .WithMany(address => address.Users)
        .UsingEntity<UserAddress>
        (pt => pt.HasOne<Address>().WithMany(),
            pt => pt.HasOne<User>().WithMany())
        .Property(pt => pt.CreatedAt)
        .HasColumnType("timestamp without time zone")
        .HasDefaultValueSql("NOW()")
        .ValueGeneratedOnAdd();
}

Related