0

我定义了以下模型:

public class Account {
   public int Id {get; set;}
   ... // other account properties

   public ICollection<AccountAddress> Addresses {get; set;}
}

public class Address {
    public int Id {get; set;}
    public string Street1 {get; set;}
    public string Street2 {get; set;}
    ... // other standard address properties
}

public class AccountAddress : Address {
  public int AccountId {get; set;}
  public DateTime? BeginDate {get; set;}
  public string Notes {get; set;}
  ... // other account address specific properties
}

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

这个想法是任何地址都可以绑定到任何帐户以及任何站点。但是,只要地址与帐户相关联,就可能需要存储有关该地址的其他信息。

由于 AccountAddress 继承自 Address,我想使用 TPT(按类型表)继承将 Address 属性映射到 Address 表,并将扩展属性映射到扩展地址属性表。

我试过这个:

public class AccountConfiguration : EntityTypeConfiguration<Account>
{
    public AccountConfiguration()
    {
        ToTable("Accounts");
        HasKey(a => a.Id);
        HasMany(a => a.Addresses).WithMany().Map(x =>
        {
           x.MapLeftKey("accountId");
           x.MapRightKey("addressId");
           x.ToTable("accountaddresses");
        }
     }
 }

 public class AddressConfiguration : EntityTypeConfiguration<Address>
 {
     public AddressConfiguration()
     {
         ToTable("addresses");
         HasKey(a => a.Id);
         ... // other property mappings
     }
 }

 public class AccountAddressConfiguration : EntityTypeConfiguration<AccountAddress>
 {
     public AccountAddressConfiguration() 
     {
        ToTable("addressextended");
        ... //other property mappings
     }
  }

这里的问题是没有定义任何东西来将 accountId 映射到 addressextended 表中。因此,如果 ID 为 40 的地址与两个不同的帐户相关联,请执行以下查询:

var _account = _context.Accounts
   .Include(a => a.Addresses)
   .SingleOrDefault(a => a.Id = 1234);

有时会为错误的帐户提供扩展属性。

我需要做什么才能使它正常工作?

编辑: 虽然接受的答案没有具体回答我的问题(即如何定义两个实体之间的多对多关系,其中一个实体是用 TPT 继承映射定义的),但它确实为提出可接受的解决方法提供了一些帮助.

我确实放弃了实体继承,只是将地址添加为我的 AccountAddress 实体的属性。然后我给了 AccountAddress(地址扩展表)它自己的主 ID。我将 accountaddresses 表更改为包含 account id 和 accountaddress id(addressextended 表的新 id)的连接表。

我还必须在 AccountAddress 中添加一个导航属性以获取 Address 和一个映射来配合它。

4

2 回答 2

1

我相信您可以通过更改查看“AccountAddress”和“SiteAddress”表的方式来解决此问题。与其将它们作为地址的子类,不如让它们成为“连接表”。AccountAddress 实体连接地址和帐户,因此从技术上讲,它必须拥有一个帐户和一个地址。您还可以在将地址与帐户关联时指定其他相关信息(例如地址类型、清除日期等)。

据我了解,您要实现的目标是将许多地址链接到许多帐户(或站点),并保留有关每个链接的一些元数据。

public class Account {
   public int Id {get; set;}
   ... // other account properties

   public ICollection<AccountAddress> Addresses {get; set;}
}

public class Address {
    public int Id {get; set;}
    public string Street1 {get; set;}
    public string Street2 {get; set;}

    public ICollection<AccountAddresses> Accounts {get; set;} // this denotes your two-way connection with the Account entity
    ... // other standard address properties
}

public class AccountAddress {
  public int AccountId {get; set;}
  public virtual Account {get; set;} // these are your "Account" properties

  public int AddressId {get; set;}
  public virtual Address {get;set;} //these are your "Address" properties

  public DateTime? BeginDate {get; set;}
  public string Notes {get; set;}
  ... // other account address specific properties
}

该模型现在将表示以下关系:

1 个帐户 <-> * 帐户地址 * <-> 1 个地址

这通过 AccountAddress 实体模拟地址和帐户之间的多对多关系。

然后,您应该同时配置 Account 和 Address 实体以展示它们的一对多关系,例如:

modelBuilder.Entity<Account>().HasMany(a => a.AccountAddresses)
                              .WithRequired(aa => aa.Account)
                              .HasForeignKey(aa => aa.AccountId);

modelBuilder.Entity<Address>().HasMany(a => a.Accounts)
                              .WithRequired(ac => ac.Address)
                              .HasForeignKey(ac => ac.AddressId);

您可以将查询修改为如下所示:

var _account = _context.Accounts
   .Include(a => a.Addresses)
   .Include(a => a.Addresses.Address)
   .SingleOrDefault(a => a.Id = 1234);
于 2013-02-12T09:17:42.773 回答
1

Address 是一种更适合作为复杂类型而不是完整实体的类型。主要原因是地址实体永远不会被重复使用:关系可能是 1:n 但实际上它们总是 1:1。这是因为将在运行时定义关系的逻辑不适用于您从中选择正确地址的现有地址列表(因此您可以重复使用地址),但会使用用户的输入,因此您将始终创建一个新的地址实体实例。

从邮政编码表中获取地址时,您根本不需要存储它们,因此如果您要存储地址信息,则不需要将其存储为实体。

与“地址”的 m:n 关系恕我直言,永远不会在实践中使用。因此重构实体以使用 Address 作为实体内部的复杂类型。如果您需要不同的地址类型,请为不同的地址类型定义不同的复杂类型。无论如何,数据模型中的继承是您想要避免的事情,除非您计划在运行时通过多态性重用验证逻辑,否则它实际上并不是那么好:性能会受到影响并且您的模型实际上会更复杂。如果您希望有一个通用接口来处理通用地址信息,请定义 IAddress 并在您的复杂地址类型上实现它。

所以 TL;DR:将地址丢弃为实体类型并将它们定义为复杂类型并摆脱继承,这对您根本没有帮助。

于 2013-02-12T16:56:15.453 回答