サーチ…


前書き

このトピックでは、Entity Frameworkを使用して1対1型の関係をマップする方法について説明します。

1対0または1対1マッピング

だから、あなたは次のモデルを持っていると再び言いましょう:

public class Person
{
  public int PersonId { get; set; }
  public string Name { get; set; }
}

public class Car
{
  public int CarId { get; set; }
  public string LicensePlate { get; set; }
}

public class MyDemoContext : DbContext
{
  public DbSet<Person> People { get; set; }
  public DbSet<Car> Cars { get; set; }
}

そして、あなたは次のような仕様を表現できるように設定したいと考えています.1人が1台または0台の車を所有でき、すべての車が1人の人物に正確に属しています(関係は双方向であるため、CarAがPersonAに属していればPersonA ' 'CarA)。

モデルを少し変更してみましょう:ナビゲーションプロパティと外部キープロパティを追加してください:

public class Person
{
  public int PersonId { get; set; }
  public string Name { get; set; }
  public int CarId { get; set; }
  public virtual Car Car { get; set; }
}

public class Car
{
  public int CarId { get; set; }
  public string LicensePlate { get; set; }
  public int PersonId { get; set; }
  public virtual Person Person { get; set; }
}

そして設定:

public class CarEntityTypeConfiguration : EntityTypeConfiguration<Car>
{
  public CarEntityTypeConfiguration()
  {
     this.HasRequired(c => c.Person).WithOptional(p => p.Car);                        
  }
}    

この時までに、これは自明であるべきです。車には必要な人物( HasRequired() )があり、その人にはオプションの車( WithOptional() )があります。この関係をどちらの側から設定するかは関係ありませんが、Has / WithとRequired / Optionalの適切な組み合わせを使用する場合は注意してください。 Person側から見ると、次のようになります。

public class PersonEntityTypeConfiguration : EntityTypeConfiguration<Person>
{
  public PersonEntityTypeConfiguration()
  {
     this.HasOptional(p => p.Car).WithOptional(c => c.Person);                        
  }
}    

さて、dbスキーマを見てみましょう:

密接に見てください: Carに言及するために、 PeopleにはFKがないことがわかります。また、 CarのFKはPersonIdではなくCarIdです。 FKの実際のスクリプトは次のとおりです。

ALTER TABLE [dbo].[Cars]  WITH CHECK ADD  CONSTRAINT [FK_dbo.Cars_dbo.People_CarId] FOREIGN KEY([CarId])
REFERENCES [dbo].[People] ([PersonId])

これは、モデルにあるCarIdPersonId foregnのキープロパティは基本的に無視されることを意味します。それらはデータベースにありますが、期待されるように外部キーではありません。これは、1対1のマッピングではFKをEFモデルに追加できないためです。リレーショナルデータベースでは1対1のマッピングがかなり問題になるからです。

アイデアは、すべての人がちょうど1台の車を所有でき、その車はその人にしか属していないということです。または、車に関連付けられていない人物の記録があるかもしれません。

だから、これはどのように外部キーで表現できますか?もちろん、そこに可能性がPersonIdCar 、およびCarIdPeople 。すべての人が、一つだけの車を持つことができることを強制するために、 PersonId内で一意でなければならないであろうCarPersonIdPeopleで一意であれば、 PersonIdNULL (所有者を持たない複数の車)の場合、どのように複数のレコードを追加できますか?回答:できません(実際は、SQL Server 2008以降でフィルタリングされたユニークなインデックスを作成できますが、他のRDBMSはもちろんのこと、このテクニカルを忘れてみましょう)。あなたが関係の両端を指定する場合はもちろん...

PeopleテーブルとCarテーブルに同じプライマリキー(接続されたレコード内の同じ値)がある場合、このルールを適用する唯一の実際の方法です。そして、これを行うには、 CarIdCar人々のPKにPKとFKの両方でなければなりません。そして、これによってスキーマ全体が混乱する。私がこれを使うとき、私はCar PersonId PK / FKに名前を付け、それに応じて設定します:

public class Person
{
  public int PersonId { get; set; }
  public string Name { get; set; }        
  public virtual Car Car { get; set; }
}

public class Car
{        
  public string LicensePlate { get; set; }
  public int PersonId { get; set; }
  public virtual Person Person { get; set; }
}

public class CarEntityTypeConfiguration : EntityTypeConfiguration<Car>
{
  public CarEntityTypeConfiguration()
  {
     this.HasRequired(c => c.Person).WithOptional(p => p.Car);
     this.HasKey(c => c.PersonId);
  }
}

理想的ではありませんが、少し良いかもしれません。それでも、このソリューションを使用する場合は、通常の命名規則に反するため、警告を発する必要があります。このモデルから生成されたスキーマは次のとおりです。

したがって、この関係はデータベーススキーマによって強制されるのではなく、Entity Framework自体によって適用されます。だからこそあなたはこれを使うときに非常に慎重でなければなりません。

1対1のマッピング

1対1のマッピング(両側が必要な場合)も難しいことです。

これを外部キーでどのように表現できるかを想像してみましょう。ここでも、 CarIdPeopleを指しCarIdCar 、そしてPersonIdを指し車でPersonIdPeople

車のレコードを挿入する場合はどうなりますか?これを成功させるためには、このカーレコードにPersonId指定されている必要があります。このPersonIdを有効にするには、 Peopleの対応するレコードが存在する必要があります。それでは、人物のレコードを挿入してみましょう。しかし、これが成功するためには、有効なCarIdが人物記録になければなりませんが、その車はまだ挿入されていません!参照された人物のレコードを最初に挿入する必要があるため、できません。しかし、参照された人物レコードは、車のレコードを参照するため挿入することはできません。最初に挿入する必要があります(外部キー - ception :))。

だから、これは論理的な方法で表現することもできません。ここでも、外部キーのいずれかを削除する必要があります。あなたが落とすのはあなた次第です。外部キーが残されている側を「従属」と呼び、外部キーなしで残っている側を「プリンシパル」と呼びます。また、依存関係の一意性を保証するために、PKはFKでなければなりません。したがって、FK列を追加してモデルにインポートすることはサポートされていません。

ここに設定があります:

public class CarEntityTypeConfiguration : EntityTypeConfiguration<Car>
{
  public CarEntityTypeConfiguration()
  {
    this.HasRequired(c => c.Person).WithRequiredDependent(p => p.Car);
    this.HasKey(c => c.PersonId);
  }
}

これで、あなたは本当にそれの論理を得ているはずです:)あなたはもう片方を選ぶこともできることを覚えておいてください。依存関係/プリンシパルバージョンのWithRequiredを使用することに注意してください。

public class PersonEntityTypeConfiguration : EntityTypeConfiguration<Person>
{
  public PersonEntityTypeConfiguration()
  {
    this.HasRequired(p => p.Car).WithRequiredPrincipal(c => c.Person);
  }
}

DBスキーマをチェックすると、1対1またはゼロ解決の場合とまったく同じであることがわかります。もう一度、これはスキーマによって強制されるのではなく、EF自体によって実行されるからです。だから、再び注意してください:)

1または0対1またはゼロのマッピング

最後に、両側がオプションの場合を簡単に見てみましょう。

ここまでで、これらの例では本当に退屈しているはずです。だから、私は詳細に入りませんし、2つのFK-sと潜在的な問題を抱えていて、これらの規則を強制しない危険性について警告します。 EFそのものの中にあります。

適用する必要がある設定は次のとおりです。

public class CarEntityTypeConfiguration : EntityTypeConfiguration<Car>
{
  public CarEntityTypeConfiguration()
  {
    this.HasOptional(c => c.Person).WithOptionalPrincipal(p => p.Car);
    this.HasKey(c => c.PersonId);
  }
}

もう一度、反対側からも設定できます。正しい方法を使用するように注意してください:)



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow