エンティティ間の関係を作成する方法は?
Entity Framework Code First アプローチを使用すると、プレーン クラスとしてモデルを作成し、ドメイン モデルまたはエンティティ クラスからデータベースを作成できます。Code First アプローチでは、データベースはクラスから作成されます。
Entity Framework Code Firstアプローチには、次のような利点があります(Scott Guのブログで述べられています)。
- デザイナを開いたり、XML マッピング ファイルを定義したりすることなく開発できます
- 基本クラスを必要としない「単純な古いクラス」を記述するだけで、モデルオブジェクトを定義します
- 「設定よりも規約」のアプローチを使用して、明示的に何も設定せずにデータベースの永続性を実現
- 必要に応じて、規則ベースの永続性をオーバーライドし、fluent コード API を使用して永続性マッピングを完全にカスタマイズします
むしろ、理論的な概念をさらに掘り下げるために、この投稿では、Code Firstアプローチを使用して、コードに直接ジャンプし、テーブルとデータベースを作成します。この投稿では、Entity Framework Code First アプローチでエンティティとエンティティ間の関係を作成する方法を学習します。EF Code First アプローチでは、エンティティ間のリレーションシップを作成するための 2 つのオプションがあります。
- データ注釈
- Fluent API
この投稿では、データ注釈を使用してエンティティ間の関係を作成します。
1つのテーブルでデータベースを作成
まず、Code First アプローチでデータベースに Student という名前のテーブルを作成することから始めましょう。ドメイン クラス Student は、次のリストに示すように作成できます。
namespace CodeFirstDemoApp
{
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
}
既にお気づきかもしれませんが、Student クラスはプレーンなクラスです。Entity Framework は Student クラスを使用して、データベースにテーブルを作成します。Student クラスはドメイン エンティティを表し、データベースの情報や参照を持つことはできません。Entity Framework は Student クラスを使用して Student テーブルを作成します。
ドメイン エンティティ クラスが作成されたら、次に、DataContext クラスを継承する Context クラスを作成する必要があります。コンテキストクラスは、次のリストに示すように作成できます。
using System.Data.Entity;
namespace CodeFirstDemoApp
{
public class Context : DbContext
{
public Context() : base()
{
}
public DbSet<Student> Students { get; set; }
}
}
デフォルトのコンストラクタを使用してContextクラスを作成しました。この投稿の後半では、コンストラクターのさまざまなオプションについて説明します。コンテキストクラスでは、次のタスクを実行しています。
- デフォルトのコンストラクターを作成する。コンストラクターにパラメーターを渡していないため、EF はNamespace.Class name という名前でデータベースを作成します。したがって、この場合、作成されるデータベース名はCodeFirstDemo.Contextになります。
- Context クラスのコンストラクターに接続文字列情報を渡していないため、EF は SQL Server Express の既定のデータベース サーバーにデータベースを作成します。
- 目的のサーバーに目的の名前でデータベースを作成するには、接続文字列を作成し、それを Context コンストラクタのパラメーターとして渡す必要があります。
- データベースにテーブルを作成するには、汎用 DbSet 型のパブリック プロパティを作成し、ドメイン エンティティが渡されます。
ここまでで、StudentエンティティクラスとContextクラスを作成しました。これで、単純な LINQ to Entity クエリを記述してデータベースを作成し、次のリストに示すように操作を実行できます。
using System;
using System.Linq;
namespace CodeFirstDemoApp
{
class Program
{
static void Main(string[] args)
{
CreateStudent();
Console.WriteLine("Student Created");
using (Context c = new Context())
{
var result = from r in c.Students select r;
foreach (var r in result)
{
Console.WriteLine(r.Name);
}
}
Console.ReadKey(true);
}
static void CreateStudent()
{
Student s = new Student
{
Id = 1,
Age = 12,
Name = "Foo"
};
using (Context c = new Context())
{
c.Students.Add(s);
c.SaveChanges();
}
}
}
}
Custom Database Name
Context クラスの既定のコンストラクターを使用する場合、EF は既定でNamespace.Contextclass name という完全修飾名でデータベースを作成します。ただし、この場合、以下のリストに示すように、コンストラクタでデータベースmydbの目的の名前を渡すことができます。
public Context()
: base("mydb")
{}
SQL Express では、EF は mydb という名前のデータベースを作成します。
接続文字列の操作
現時点では、データベースの作成を EF に依存しています。ただし、接続文字列を渡して、目的のサーバーにデータベースを作成し、名前を付けることができます。接続文字列は、以下に示すように設定ファイルに作成できます。
<connectionStrings> <add name="democonnectionstring" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=Demo1;Integrated Security=True;MultipleActiveResultSets=true" providerName="System.Data.SqlClient" /></connectionStrings>
ローカルのdbサーバーにデータベースを作成するための接続文字列を作成しました。次に、以下のリストに示すように、Contextクラスのコンストラクタに接続文字列名を渡す必要があります。
public Context() : base("name=democonnectionstring") {}
Relationship Between Entities
Code First アプローチでは、次の 2 つのオプションのいずれかを使用してエンティティ間のリレーションシップを作成できます。
- データ注釈
- Fluent API
この投稿では、データ注釈を使用して関係を作成します。
1 対 1 の関係
2つのエンティティ間に1対1の関係を作成する必要がある場合があります。つまり、2つのエンティティ間に主キーと外部キーの関係が必要です。2つのエンティティと次のルールがあるとします。
- Student と StudentAccount という名前の 2 つのエンティティがあります
- 学生が主要なエンティティである
- StudentAccount は Student の従属エンティティです
- StudentAccountの主キーはStudentの外部キーになります
StudentAccountは、StudentAccountなしでは作成できないはずであり、StudentAccountにはStudentのエントリが1つしか存在できません。簡単に言うと、各学生は1つのStudentAccountを持ち、StudentがいないとStudentAccountは存在しません。
まず、プライマリ エンティティである Student を作成しましょう。
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public virtual StudentAccount StudentAccount { get; set; }
}
お気づきかもしれませんが、Student エンティティには、次のリストに示すように作成される StudentAccount 型の仮想プロパティがあります。
public class StudentAccount {
public int Id {
get;
set;
}
public string Name {
get;
set;
}
public int Amount {
get;
set;
}
[Required]
public virtual Student Student {
get;
set;
}
}
ここでも、StudentAccount エンティティに Student 型の仮想プロパティがあることに気付いたかもしれません。Student はプライマリ エンティティであるため、StudentAccount エンティティの仮想 Student プロパティにはRequiredという注釈が付けられます。さらに、次のリストに示すように、Context クラスを作成できます。
using System.Data.Entity;
namespace CodeFirstDemoApp {
public class Context : DbContext {
public Context() : base("name=democonnectionstring") {}
public DbSet<Student>Students {
get;
set;
}
public DbSet<StudentAccount>StudentAccounts {
get;
set;
}
}
}
StudentAccounts テーブルに対応する行が Student ないと、テーブルに行を作成できないことを常に覚えておいてください データは、次のリストに示すように、関連テーブルに作成できます。
static void CreateStudent() {
Student s=new Student {
Id=1,
Age=12,
Name="Foo"
};
StudentAccount sa=new StudentAccount {
Amount=300,
Name="Sports Account",
Student=s
};
Context c=new Context();
c.Students.Add(s);
c.StudentAccounts.Add(sa);
c.SaveChanges();
}
お気づきかもしれませんが、Student のオブジェクトを StudentAccount のプロパティとして設定しています 次のリストに示すように、両方のテーブルからレコードを取得できます。
Context c=new Context();
var result=from r in c.Students select r;
foreach (var r in result) {
Console.WriteLine(r.Name);
Console.WriteLine(r.StudentAccounts.Amount);
}
SQL Server Management Studio でエンティティ間の関係を確認するために、次の図に示すように、制約とキーを使用して作成された列を確認できます。

ここでは、StudentAccounts テーブルの Id 列が主キーと外部キーの両方です。
1 対多の関係
2つのエンティティ間に1つの関係を作成しすぎる必要がある場合があります。2つのエンティティがあるとします
- Student と StudentAddress の 2 つのエンティティがあります
- 学生が主要なエンティティである
- StudentAddress は Student の従属エンティティです
- 1人の学生が複数のStudentAddressに登録できます
1 人の学生が複数の StudentAddress を持つことができます。StudentAddress の列の 1 つには、Student の主キーとして外部キーがあります。
まず、主エンティティ Student を作成しましょう。
public class Student {
public Student() {
StudentAddresses=new HashSet<StudentAddress>();
}
public int Id {
get;
set;
}
public string Name {
get;
set;
}
public int Age {
get;
set;
}
public ICollection<StudentAddress>StudentAddresses {
get;
set;
}
}
StudentAddress のコレクションのプロパティを作成し、次に Student のコンストラクターで StudentAddress プロパティの設定値を作成していることに気付いたかもしれません。StudentAddress クラスは、次のリストに示すように作成できます。
public class StudentAddress {
public int Id {
get;
set;
}
public string Address {
get;
set;
}
public int StudentId {
get;
set;
}
public virtual Student Student {
get;
set;
}
}
ここでも、StudentAddress エンティティに Student 型の仮想プロパティがあることに気付いたかもしれません。Student はプライマリ エンティティであるため、StudentAddress の仮想 Student プロパティには、対応する StudentId プロパティがあります。
さらに、次のリストに示すように、Context クラスを作成できます。
public class Context : DbContext {
public Context() : base("name=democonnectionstring") {}
public DbSet<Student>Students {
get;
set;
}
public DbSet<StudentAddress>StudentAddresses {
get;
set;
}
}
StudentAddress テーブルに対応する行が Student テーブルにない限り、テーブルに行を作成できないことを常に覚えておいてください。データは、次のリストに示すように、関連テーブルに作成できます。
static void CreateStudent() {
Student s=new Student {
Id=1,
Age=12,
Name="Foo"
};
StudentAddress sa1=new StudentAddress {
Address="Delhi",
Id=1
};
StudentAddress sa2=new StudentAddress {
Address="Bangalore",
Id=2
};
s.StudentAddresses.Add(sa1);
s.StudentAddresses.Add(sa2);
Context c=new Context();
c.Students.Add(s);
c.SaveChanges();
}
お気づきかもしれませんが、StudentAddress のオブジェクトを Student. に追加しています。次のリストに示すように、両方のテーブルからレコードを取得できます。
static void Main(string[] args) {
CreateStudent();
Console.WriteLine("Student Created");
Context c=new Context();
var result=from r in c.Students.Include("StudentAddresses") select r;
foreach (var r in result) {
Console.WriteLine(r.Name);
foreach(var a in r.StudentAddresses) {
Console.WriteLine(a.Address);
}
}
Console.ReadKey(true);
}
SQL Server Management Studio でエンティティ間の関係を確認するために、次の図に示すように、制約とキーを使用して作成された列を確認できます。

Many to Many Relationship
最後になりましたが、多対多の関係をどのように構成できるかを見てみましょう。たとえば、Student エンティティと Subject エンティティがあるとします。1人の学生が複数の科目に登録でき、1つの科目に複数の学生が登録できます。これらのエンティティ間に多数のリレーションシップを作成するには、まず、次のリストに示すように Student エンティティを作成しましょう。
public class Student {
public Student() {
Subjects=new HashSet<Subject>();
}
public int Id {
get;
set;
}
public string Name {
get;
set;
}
public int Age {
get;
set;
}
public ICollection<Subject>Subjects {
get;
set;
}
}
ここでは、Subjects のコレクションのプロパティを作成し、Student のコンストラクタで Subjects プロパティの設定値を作成しています。Subject クラスは、次のリストに示すように作成できます。
public class Subject {
public Subject() {
Students=new HashSet<Student>();
}
public int Id {
get;
set;
}
public string Name {
get;
set;
}
public virtual ICollection<Student>Students {
get;
set;
}
}
Subjectクラスでは、Studentのコレクションのプロパティを作成し、Subjectクラスのコンストラクタでは、学生のセットを作成しています。エンティティ間にあまりにも多くの関係を作成するために必要なのはこれだけです。
さらに、次のリストに示すように、Context クラスを作成できます。
public class Context : DbContext {
public Context() : base("name=democonnectionstring") {}
public DbSet<Student>Students {
get;
set;
}
public DbSet<Subject>Subjects {
get;
set;
}
}
次のリストに示すように、Students and Subjects テーブルに行を作成できます。
static void CreateStudent() {
Student s=new Student {
Id=1,
Age=12,
Name="Foo"
};
Subject s1=new Subject {
Id=1,
Name="Phy"
};
Subject s2=new Subject {
Id=2,
Name="Maths"
};
s.Subjects.Add(s1);
s.Subjects.Add(s2);
Context c=new Context();
c.Students.Add(s);
c.SaveChanges();
}
次に示すように、両方のテーブルからレコードを取得できます。
static void Main(string[] args) {
CreateStudent();
Console.WriteLine("Student Created");
Context c=new Context();
var result=from r in c.Students.Include("Subjects") select r;
foreach (var r in result) {
Console.WriteLine(r.Name);
foreach(var a in r.Subjects) {
Console.WriteLine(a.Name);
}
}
Console.ReadKey(true);
}
Student エンティティと Subject エンティティの間のリレーションシップを確認すると、EF が多対多の関係を維持するために追加のテーブルを作成したことがわかります

以上が、Code Firstアプローチでエンティティ間の関係を作成する方法です。この投稿では、単一のエンティティの操作から始めて、エンティティ間の関係の作成に進みました。この投稿がお役に立てば幸いです、読んでくれてありがとう。
Infragistics Ultimate 15.2 がリリースされました。ダウンロードして、そのパワーを実際に見てみましょう!
