简体   繁体   English

一对多 (EF Core) 的建议

[英]Recommendations for a One to Many (EF Core)

I'm trying to figure out the best way to define a one to many relationship table as it pertains to Customers and Addresses.我试图找出定义与客户和地址有关的一对多关系表的最佳方法。 Each Customer can have multiple address (Mailing, Billing, Delivery, etc).每个客户可以有多个地址(邮寄、账单、交付等)。 The Type of address is stored in a separate table (AddressType).地址的类型存储在一个单独的表 (AddressType) 中。

Here's what I have:这是我所拥有的:

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; }
    }

Couple of questions...几个问题...

  1. Would what I have above be considered good practice?我上面的内容会被认为是好的做法吗? If not, how would you define it?如果不是,你会如何定义它?
  2. Assuming that the AddressType table contains Mailing, Billing and Delivery, how would I issue a Linq query where I only want to pull the Mailing Address?假设 AddressType 表包含 Mailing、Billing 和 Delivery,我将如何发出 Linq 查询,而我只想提取 Mailing Address?

Thanks a bunch.谢谢一堆。

--- Val --- 值

I'd suggest a 'base' address class.我建议使用“基本”地址 class。 Mailing, Billing, Delivery etc. would inherit from this base class. Mailing、Billing、Delivery 等将从这个基础 class 继承。

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; }
}

In case of delivery, you might want to print a delivery note with the address label for the delivery driver.在送货的情况下,您可能需要为送货司机打印地址为 label 的送货单。 But is does not make sense to include a DeliveryNote in the base address class, because when would a billing address need a delivery note?但是在基本地址 class 中包含 DeliveryNote 是没有意义的,因为账单地址什么时候需要送货单?

So you inherit from your base Address class to create specific address types.因此,您从基本地址 class 继承来创建特定的地址类型。

For example:例如:

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

Assuming you use EF Code First, Entity framework creates an Address table, with a discriminator column.假设您使用 EF Code First,实体框架会创建一个Address表,其中包含一个discriminator列。 When you save a new address, the discriminator column defines the type of address.保存新地址时, 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();

Now to query the companies and specify the type of address you need, you just need to make a call to include and let EF Core include the address.现在要查询公司并指定您需要的地址类型,您只需调用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();

The EF Fluent API configuration should be something like this: 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; }
        

The result would look like this:结果将如下所示:

Address Table (I left out some columns for conciseness)地址表(为了简洁,我省略了一些列)

在此处输入图像描述

Companies Table (I left out some columns for conciseness)公司表(为简洁起见,我省略了一些列)

在此处输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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