EF Core Net 5 - Code First - 与同一实体的多种关系
EF Core Net 5 - Code First - Multiple relationships to same entity
我正在尝试设置两个实体之间的多重关系,如下所示:
一个公司有多个地址。
一家公司有一个默认地址。
一家公司有一个默认账单地址。
一家公司有一个默认收货地址。
public abstract class BaseAddress : AbstractValidatableEntity
{
public AddressType Type { get; set; }
public AddressStatus Status { get; set; }
public Country Country { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string Address3 { get; set; }
public string Address4 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
}
public class CompanyAddress : BaseAddress
{
public Guid CompanyId { get; set; }
public Company Company { get; set; }
}
public class Company : AbstractValidatableEntity
{
public string Name { get; set; }
public List<User> Users { get; set; }
public Guid OwnerId { get; set; }
public User Owner { get; set; }
public List<CompanyAddress> Addresses { get; set; }
public CompanyAddress DefaultAddress { get; set; }
public CompanyAddress DefaultBillingAddress { get; set; }
public CompanyAddress DefaultDeliveryAddress { get; set; }
}
public class CompanyConfiguration : AbstractEntityConfiguration<Company>
{
public override void Configure(EntityTypeBuilder<Company> builder)
{
base.Configure(builder);
// Table name
builder
.ToTable("Companies");
// Columns
builder
.Property(s => s.Name)
.IsRequired(true)
.HasMaxLength(255);
// Relationships
builder
.HasMany(s => s.Users)
.WithOne(u => u.Company)
.HasForeignKey(u => u.CompanyId)
.IsRequired(false)
.HasConstraintName("FK_COMPANY_USERS");
builder
.HasMany(s => s.Addresses)
.WithOne(a => a.Company)
.HasForeignKey(a => a.CompanyId)
.IsRequired()
.HasConstraintName("FK_COMPANY_ADDRESSES")
.OnDelete(DeleteBehavior.Cascade);
builder
.HasOne(s => s.DefaultAddress)
.WithOne()
.HasForeignKey<CompanyAddress>(da => da.CompanyId)
.IsRequired(false)
.HasConstraintName("FK_COMPANY_DEFAULT_ADDRESS")
.OnDelete(DeleteBehavior.Restrict);
builder
.HasOne(s => s.DefaultBillingAddress)
.WithOne()
.HasForeignKey<CompanyAddress>(da => da.CompanyId)
.IsRequired(false)
.HasConstraintName("FK_COMPANY_DEFAULT_BILLING_ADDRESS")
.OnDelete(DeleteBehavior.Restrict);
builder
.HasOne(s => s.DefaultDeliveryAddress)
.WithOne()
.HasForeignKey<CompanyAddress>(da => da.CompanyId)
.HasConstraintName("FK_COMPANY_DEFAULT_DELIVERY_ADDRESS");
// Indexes
builder
.HasIndex(s => s.Name)
.HasDatabaseName("IX_COMPANY_NAME");
}
}
但是在创建数据库时出现以下错误:
System.InvalidOperationException: 'Unable to determine the relationship represented by navigation 'Company.Addresses' of type 'List'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.'
请注意,我试图实现 1 个多对一关系和 3 个一对一关系 table,这与我在此处搜索的所有其他问题不同。
我读过多个类似的问题,但它们都有以下情况:
一个公司有多个地址。
一家公司有一个默认地址。
如果我删除代码中的第二个和第三个一对一关系,它将完美运行。我不确定在代码方面该怎么做。
我知道我可以在数据库方面做到这一点。拥有一个 CompanyAdresses table 并在 Company table 上拥有这些属性:DefaultAddressId、DefaultBillingAddressId、DefaultDeliveryAddressId。
在此先感谢大家。
对于具有不同语义的 Company 和 Address 之间的每个关系,您应该有一个 ForeignKey。例如:
public class Company : AbstractValidatableEntity
{
public string Name { get; set; }
public List<User> Users { get; set; }
public Guid OwnerId { get; set; }
public User Owner { get; set; }
public List<CompanyAddress> Addresses { get; set; }
public CompanyAddress DefaultAddress { get; set; }
public CompanyAddress DefaultBillingAddress { get; set; }
public CompanyAddress DefaultDeliveryAddress { get; set; }
public Guid DefaultAddressId { get; set; }
public Guid DefaultBillingAddressId { get; set; }
public Guid DefaultDeliveryAddressId { get; set; }
}
然后,用自己的 FK 配置每个关系。
...
builder
.HasOne(s => s.DefaultAddress)
.WithOne()
.HasForeignKey<Company>(da => da.DefaultAddressId)
.IsRequired(false)
.HasConstraintName("FK_COMPANY_DEFAULT_ADDRESS")
.OnDelete(DeleteBehavior.Restrict);
builder
.HasOne(s => s.DefaultBillingAddress)
.WithOne()
.HasForeignKey<Company>(da => da.DefaultBillingAddressId)
.IsRequired(false)
.HasConstraintName("FK_COMPANY_DEFAULT_BILLING_ADDRESS")
.OnDelete(DeleteBehavior.Restrict);
builder
.HasOne(s => s.DefaultDeliveryAddress)
.WithOne()
.HasForeignKey<Company>(da => da.DefaultDeliveryAddressId)
.HasConstraintName("FK_COMPANY_DEFAULT_DELIVERY_ADDRESS");
...
您可以查看 and 个相关答案。
这是处理此问题并将关系直接配置到模型中的另一种方法。
public class Company : AbstractValidatableEntity
{
public string Name { get; set; }
public List<User> Users { get; set; }
public Guid OwnerId { get; set; }
public User Owner { get; set; }
[InverseProperty("Companies")]
public List<Address> Addresses { get; set; }
[InverseProperty("HostedCompanies")]
[ForeignKey("DefaultAdressID")]
public Address DefaultAddress { get; set; }
public Guid DefaultAddressID { get; set; }
[InverseProperty("BillingCompanies")]
[ForeignKey("DefaultBillingAddressID")]
public Address DefaultBillingAddress { get; set; }
public Guid DefaultBillingAddressID { get; set; }
[InverseProperty("DeliveryCompanies")]
[ForeignKey("DefaultDeliveryAddressID")]
public Address DefaultDeliveryAddress { get; set; }
public Guid DefaultDeliveryAddressID { get; set; }
}
在您的地址模型中添加这些
public class Address {
...
public ICollection<Company> Companies { get; set; }
public ICollection<Company> HostedCompanies { get; set; }
public ICollection<Company> BillingCompanies { get; set; }
public ICollection<Company> DeliveryCompanies{ get; set; }
...
}
现在您可以删除 CompanyAddress
class,它不再可用了。实际上,引擎盖下的 EF 会生成
CompanyAddress table 给你。你也可以清除你的 modelBuilder
:
public override void Configure(EntityTypeBuilder<Company> builder)
{
base.Configure(builder);
// Table name
builder
.ToTable("Companies");
// Columns
builder
.Property(s => s.Name)
.IsRequired(true)
.HasMaxLength(255);
// Relationships
builder
.HasMany(s => s.Users)
.WithOne(u => u.Company)
.HasForeignKey(u => u.CompanyId)
.IsRequired(false)
.HasConstraintName("FK_COMPANY_USERS");
// Indexes
builder
.HasIndex(s => s.Name)
.HasDatabaseName("IX_COMPANY_NAME");
}
我正在尝试设置两个实体之间的多重关系,如下所示:
一个公司有多个地址。
一家公司有一个默认地址。
一家公司有一个默认账单地址。
一家公司有一个默认收货地址。
public abstract class BaseAddress : AbstractValidatableEntity
{
public AddressType Type { get; set; }
public AddressStatus Status { get; set; }
public Country Country { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string Address3 { get; set; }
public string Address4 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
}
public class CompanyAddress : BaseAddress
{
public Guid CompanyId { get; set; }
public Company Company { get; set; }
}
public class Company : AbstractValidatableEntity
{
public string Name { get; set; }
public List<User> Users { get; set; }
public Guid OwnerId { get; set; }
public User Owner { get; set; }
public List<CompanyAddress> Addresses { get; set; }
public CompanyAddress DefaultAddress { get; set; }
public CompanyAddress DefaultBillingAddress { get; set; }
public CompanyAddress DefaultDeliveryAddress { get; set; }
}
public class CompanyConfiguration : AbstractEntityConfiguration<Company>
{
public override void Configure(EntityTypeBuilder<Company> builder)
{
base.Configure(builder);
// Table name
builder
.ToTable("Companies");
// Columns
builder
.Property(s => s.Name)
.IsRequired(true)
.HasMaxLength(255);
// Relationships
builder
.HasMany(s => s.Users)
.WithOne(u => u.Company)
.HasForeignKey(u => u.CompanyId)
.IsRequired(false)
.HasConstraintName("FK_COMPANY_USERS");
builder
.HasMany(s => s.Addresses)
.WithOne(a => a.Company)
.HasForeignKey(a => a.CompanyId)
.IsRequired()
.HasConstraintName("FK_COMPANY_ADDRESSES")
.OnDelete(DeleteBehavior.Cascade);
builder
.HasOne(s => s.DefaultAddress)
.WithOne()
.HasForeignKey<CompanyAddress>(da => da.CompanyId)
.IsRequired(false)
.HasConstraintName("FK_COMPANY_DEFAULT_ADDRESS")
.OnDelete(DeleteBehavior.Restrict);
builder
.HasOne(s => s.DefaultBillingAddress)
.WithOne()
.HasForeignKey<CompanyAddress>(da => da.CompanyId)
.IsRequired(false)
.HasConstraintName("FK_COMPANY_DEFAULT_BILLING_ADDRESS")
.OnDelete(DeleteBehavior.Restrict);
builder
.HasOne(s => s.DefaultDeliveryAddress)
.WithOne()
.HasForeignKey<CompanyAddress>(da => da.CompanyId)
.HasConstraintName("FK_COMPANY_DEFAULT_DELIVERY_ADDRESS");
// Indexes
builder
.HasIndex(s => s.Name)
.HasDatabaseName("IX_COMPANY_NAME");
}
}
但是在创建数据库时出现以下错误:
System.InvalidOperationException: 'Unable to determine the relationship represented by navigation 'Company.Addresses' of type 'List'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.'
请注意,我试图实现 1 个多对一关系和 3 个一对一关系 table,这与我在此处搜索的所有其他问题不同。
我读过多个类似的问题,但它们都有以下情况:
一个公司有多个地址。
一家公司有一个默认地址。
如果我删除代码中的第二个和第三个一对一关系,它将完美运行。我不确定在代码方面该怎么做。
我知道我可以在数据库方面做到这一点。拥有一个 CompanyAdresses table 并在 Company table 上拥有这些属性:DefaultAddressId、DefaultBillingAddressId、DefaultDeliveryAddressId。
在此先感谢大家。
对于具有不同语义的 Company 和 Address 之间的每个关系,您应该有一个 ForeignKey。例如:
public class Company : AbstractValidatableEntity
{
public string Name { get; set; }
public List<User> Users { get; set; }
public Guid OwnerId { get; set; }
public User Owner { get; set; }
public List<CompanyAddress> Addresses { get; set; }
public CompanyAddress DefaultAddress { get; set; }
public CompanyAddress DefaultBillingAddress { get; set; }
public CompanyAddress DefaultDeliveryAddress { get; set; }
public Guid DefaultAddressId { get; set; }
public Guid DefaultBillingAddressId { get; set; }
public Guid DefaultDeliveryAddressId { get; set; }
}
然后,用自己的 FK 配置每个关系。
...
builder
.HasOne(s => s.DefaultAddress)
.WithOne()
.HasForeignKey<Company>(da => da.DefaultAddressId)
.IsRequired(false)
.HasConstraintName("FK_COMPANY_DEFAULT_ADDRESS")
.OnDelete(DeleteBehavior.Restrict);
builder
.HasOne(s => s.DefaultBillingAddress)
.WithOne()
.HasForeignKey<Company>(da => da.DefaultBillingAddressId)
.IsRequired(false)
.HasConstraintName("FK_COMPANY_DEFAULT_BILLING_ADDRESS")
.OnDelete(DeleteBehavior.Restrict);
builder
.HasOne(s => s.DefaultDeliveryAddress)
.WithOne()
.HasForeignKey<Company>(da => da.DefaultDeliveryAddressId)
.HasConstraintName("FK_COMPANY_DEFAULT_DELIVERY_ADDRESS");
...
您可以查看
这是处理此问题并将关系直接配置到模型中的另一种方法。
public class Company : AbstractValidatableEntity
{
public string Name { get; set; }
public List<User> Users { get; set; }
public Guid OwnerId { get; set; }
public User Owner { get; set; }
[InverseProperty("Companies")]
public List<Address> Addresses { get; set; }
[InverseProperty("HostedCompanies")]
[ForeignKey("DefaultAdressID")]
public Address DefaultAddress { get; set; }
public Guid DefaultAddressID { get; set; }
[InverseProperty("BillingCompanies")]
[ForeignKey("DefaultBillingAddressID")]
public Address DefaultBillingAddress { get; set; }
public Guid DefaultBillingAddressID { get; set; }
[InverseProperty("DeliveryCompanies")]
[ForeignKey("DefaultDeliveryAddressID")]
public Address DefaultDeliveryAddress { get; set; }
public Guid DefaultDeliveryAddressID { get; set; }
}
在您的地址模型中添加这些
public class Address {
...
public ICollection<Company> Companies { get; set; }
public ICollection<Company> HostedCompanies { get; set; }
public ICollection<Company> BillingCompanies { get; set; }
public ICollection<Company> DeliveryCompanies{ get; set; }
...
}
现在您可以删除 CompanyAddress
class,它不再可用了。实际上,引擎盖下的 EF 会生成
CompanyAddress table 给你。你也可以清除你的 modelBuilder
:
public override void Configure(EntityTypeBuilder<Company> builder)
{
base.Configure(builder);
// Table name
builder
.ToTable("Companies");
// Columns
builder
.Property(s => s.Name)
.IsRequired(true)
.HasMaxLength(255);
// Relationships
builder
.HasMany(s => s.Users)
.WithOne(u => u.Company)
.HasForeignKey(u => u.CompanyId)
.IsRequired(false)
.HasConstraintName("FK_COMPANY_USERS");
// Indexes
builder
.HasIndex(s => s.Name)
.HasDatabaseName("IX_COMPANY_NAME");
}