简体   繁体   中英

One to Many with One Main in Code-First Entity Framework Core

One company can have many addresses, however each company has a main address.

I am looking to find the best way to create this kind of relation in EF Core.

Below is what I came up with. Is there a better way? Am I way off entirely?


Models

public class Company
{
    public int Id { get; set; }

    public int MainAddressId { get; set; }
    public Address MainAddress { get; set; }

    public ICollection<CompanyAddress> CompanyAddresses { get; set; }

    // other company info
}

public class Address
{
    public int Id { get; set; }

    public int CompanyAddressId { get; set; }
    public CompanyAddress CompanyAddress { get; set; }

    // other address info
}

public class CompanyAddress
{
    public int CompanyId { get; set; }
    public Company Company { get; set; }

    public int AddressId { get; set; }
    public Address Address { get; set; }

    public bool IsMain { get; set; }
}


DataContext.cs

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

    public DbSet<Company> Companies { get; set; }
    public DbSet<Address> Addresses { get; set; }
    public DbSet<CompanyAddress> CompanyAddresses { get; set; }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        builder.Entity<CompanyAddress>()
            .HasKey(ca => new {ca.CompanyId, ca.AddressId});

        builder.Entity<CompanyAddress>()
            .HasOne(ca => ca.Company)
            .WithMany(ca => ca.CompanyAddresses)
            .HasForeignKey(ca => ca.CompanyId)
            .OnDelete(DeleteBehavior.Cascade);

        builder.Entity<CompanyAddress>()
            .HasOne(ca => ca.Address)
            .WithOne(ca => ca.CompanyAddresses)
            .HasForeignKey(ca => ca.AddressId)
            .OnDelete(DeleteBehavior.Cascade);
    }
}

In my opinion, dead on. There are always other ways. But this is straight-forward and easily understood. MainAddress and MainAddressId are redundant. You don't have lazy loading (virtual) so you can easily determine the main address by

dbContext.Companies.FirstOrDefault(p => p.Id = <myCompanyId>);
dbContext.CompanyAddresses.FirstOrDefault(p => p.CompanyId == <myCompanyId> && p.IsMain);

If you go with lazy loading later, just add .Include("Address") to the second query. And yes, you can combine the two.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM