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

アイデアは、任意のAddressを任意のAccountおよび任意のSiteに関連付けることができるということです。ただし、アドレスがアカウントに関連付けられている場合は常に、そのアドレスに関して保存する必要がある追加情報が存在する場合があります。

AccountAddress は Address から継承するため、TPT (Table Per Type) 継承を使用して、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 のアドレスが 2 つの異なるアカウントに関連付けられている場合、次のクエリを実行します。

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

間違ったアカウントの拡張プロパティを提供することがあります。

これを機能させるにはどうすればよいですか?

編集: 受け入れられた回答は私の質問に具体的に答えませんでしたが(つまり、1つのエンティティがTPT継承マッピングで定義されている2つのエンティティ間の多対多の関係をどのように定義できますか)、許容できる回避策を考え出すのに役立ちました.

エンティティの継承を削除し、単純にアドレスを AccountAddress エンティティのプロパティとして追加しました。次に、AccountAddress (addressextended テーブル) に独自のプライマリ ID を指定しました。accountaddresses テーブルを、アカウント ID と accountaddress ID (addressextended テーブルの新しい ID) を含む結合テーブルに変更しました。

また、Address の AccountAddress にナビゲーション プロパティを追加し、それに対応するマッピングを追加する必要がありました。

4

2 に答える 2

1

「AccountAddress」テーブルと「SiteAddress」テーブルの表示方法を変更することで、この問題を回避できる可能性があると思います。それらをAddressのサブクラスにする代わりに、「テーブルに参加」させてみませんか。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アカウント<->*AccountAddress *<->1アドレス

これは、AccountAddressエンティティを経由することにより、アドレスとアカウント間の多対多の関係をシミュレートします。

次に、アカウントエンティティとアドレスエンティティの両方を構成して、次のような1対多の関係を示す必要があります。

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

アドレスは、完全なエンティティとしてではなく、複合型として適しているタイプの 1 つです。主な理由は、アドレス エンティティが再利用されないことです。関係は 1:n かもしれませんが、実際には常に 1:1 です。これは、実行時に関係を定義するロジックが、適切なアドレスを選択した既存のアドレスのリストでは機能せず (アドレスを再利用できるため)、ユーザーからの入力を使用するため、常に終了するためです。新しい住所エンティティ インスタンスを作成します。

郵便番号テーブルから住所を取得する場合は、住所を保存する必要はまったくありません。したがって、住所情報を保存する場合は、エンティティとして保存する必要はありません。

「住所」との m:n の関係は、私見では実際には使用されません。そのため、エンティティをリファクタリングして、エンティティ内の複合型として Address を使用します。異なる Address タイプが必要な場合は、異なる Address タイプに対して異なる複合タイプを定義します。データモデルの継承は、実行時にポリモーフィズムを介して検証ロジックを再利用する予定がない限り、とにかく避けたいものです。それ以外の場合は、パフォーマンスが低下し、モデルが実際により複雑になります。一般的なアドレス情報に関して対話するための汎用インターフェイスが必要な場合は、IAddress を定義し、それを複雑なアドレス タイプに実装します。

TL;DR: アドレスをエンティティ型として捨て、それらを複雑な型として定義し、継承を取り除きます。ここではまったく役に立ちません。

于 2013-02-12T16:56:15.453 に答える