一对多建议(EF核心)

时间:2020-07-04 21:37:34

标签: c# entity-framework linq asp.net-core

我试图找出定义一对多关系表的最佳方法,因为它与客户和地址有关。每个客户可以有多个地址(邮寄,账单,递送等)。地址的类型存储在单独的表(AddressType)中。

这就是我所拥有的:

public class Company
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public List<Address> Addresses { get; set; }
    }

  public class Address
    {
        public int Id { get; set; }
        public int AddressTypeId { get; set; }
        public AddressType AddressType { get; set; }
        public string Street1 { get; set; }
        public string Street2 { get; set; }
        public string City { get; set; }
        public int StateId { get; set; }
        public State State { get; set; }
        public string PostalCode { get; set; }
        public int CountryId { get; set; }
        public Country Country { get; set; }
        public bool Active { get; set; }
        public int CompanyId { get; set; }
    }

    public class AddressType
    {
        public int Id { get; set; }
        public string Display { get; set; }
        public bool Active { get; set; }
    }

一对问题...

  1. 我上面所说的会被认为是好的做法吗?如果没有,您将如何定义它?
  2. 假设AddressType表包含Mailing,Billing和Delivery,我该如何在仅希望提取Mailing Address的地方发出Linq查询?

谢谢。

--- Val

1 个答案:

答案 0 :(得分:0)

我建议使用“基本”地址类别。邮件,账单,递送等都将从该基类继承。

public class Address
{
    public string Street { get; set; }

    public int HouseNumber { get; set; }

    public string HouseNumberAddition { get; set; }

    public string City { get; set; }

    public string Country { get; set; }
}

如果要送货,您可能需要打印带有送货司机地址标签的送货单。但是在基地址类中包括DeliveryNote是没有意义的,因为帐单地址何时需要交付单?

因此,您从基址类继承来创建特定的地址类型。

例如:

public class DeliveryAddress : Address
{
    public string DeliveryNote { get; set; } = "Please don't ring the bell after 10pm."
}

假设您首先使用EF代码,则实体框架将创建一个Address表,其中包含一个discriminator列。保存新地址时,discriminator列定义地址的类型。

var googleCompany = new Company
{
    DeliveryAddress = new DeliveryAddress
    {
        Street = "Google Street",
        HouseNumber = 1,
        DeliveryNote = "Watch out for the dog."
    },
    CompanyAddress = new CompanyAddress()
};

var microsoftCompany = new Company
{
    DeliveryAddress = new DeliveryAddress
    {
        Street = "Microsoft Street",
        HouseNumber = 2,
        DeliveryNote = "Don't bring an Apple device on the premise."
    },
    CompanyAddress = new CompanyAddress()
};


_context.Companies.Add(googleCompany);
_context.Companies.Add(microsoftCompany);
_context.SaveChanges();

现在要查询公司并指定所需的地址类型,只需致电include,然后让EF Core包括地址即可。

var companiesWithBothDeliveryAddress = 
    _context.Companies.Include(x => x.CompanyAddress)
                      .Include(x => x.DeliveryAddress).ToList();

var companiesWithOnlyDeliveryAddress =
    _context.Companies.Include(x => x.DeliveryAddress).ToList();

EF Fluent API配置应如下所示:

        protected override void OnModelCreating(ModelBuilder builder)
        {
            // Company to CompanyAddress, without inverse property on CompanyAddress.
            builder.Entity<Company>()
                .HasOne(x => x.CompanyAddress)
                .WithOne()
                .HasForeignKey<Company>(x => x.CompanyAddressId)
                .IsRequired(false)
                .OnDelete(DeleteBehavior.NoAction);

            // Company to DeliveryAddress, without inverse property on DeliveryAddress.
            builder.Entity<Company>()
                .HasOne(x => x.DeliveryAddress)
                .WithOne()
                .HasForeignKey<Company>(x => x.DeliveryAddressId)
                .IsRequired(false)
                .OnDelete(DeleteBehavior.NoAction);

            // We let all the Address types share the 'CompanyId' column, 
            // otherwise, EF would create a seperate CompanyId column for all of them.
            builder.Entity<Address>()
                .Property(x => x.CompanyId)
                .HasColumnName(nameof(Address.CompanyId));

            builder.Entity<CompanyAddress>()
                .Property(x => x.CompanyId)
                .HasColumnName(nameof(Address.CompanyId));            
            
            builder.Entity<DeliveryAddress>()
                .Property(x => x.CompanyId)
                .HasColumnName(nameof(Address.CompanyId));

            base.OnModelCreating(builder);
        }

        public DbSet<Address> Addresses { get; set; }

        public DbSet<DeliveryAddress> DeliveryAddresses { get; set; }

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

结果如下:

地址表(为简洁起见,我省略了一些列)

enter image description here

公司表(为简洁起见,我省略了一些列)

enter image description here