Entity-framework-first-example
Entity Framework-最初の例
クラスを使用して非常に単純なモデルを定義しましょう。 Program.csファイルで定義しているだけですが、実際のアプリケーションでは、クラスを個別のファイルに分割し、場合によっては個別のプロジェクトに分割します。 以下は、Code Firstアプローチを使用して作成するデータモデルです。
モデルを作成
Studentクラスの次のコードを使用して、Program.csファイルに次の3つのクラスを追加します。
public class Student {
public int ID { get; set; }
public string LastName { get; set; }
public string FirstMidName { get; set; }
public DateTime EnrollmentDate { get; set; }
public virtual ICollection<Enrollment> Enrollments { get; set; }
}
- IDプロパティは、このクラスに対応するデータベーステーブルの主キー列になります。
- Enrollmentsプロパティはナビゲーションプロパティです。 ナビゲーションプロパティは、このエンティティに関連する他のエンティティを保持します。
- この場合、StudentエンティティのEnrollmentsプロパティには、そのStudentエンティティに関連するすべてのEnrollmentエンティティが保持されます。
- 通常、ナビゲーションプロパティは、遅延読み込みなどの特定のEntity Framework機能を利用できるように、仮想として定義されます。
- ナビゲーションプロパティが複数のエンティティ(多対多または1対1の関係など)を保持できる場合、そのタイプは、ICollectionなどのエントリを追加、削除、更新できるリストである必要があります。
以下は、コースクラスの実装です。
public class Course {
public int CourseID { get; set; }
public string Title { get; set; }
public int Credits { get; set; }
public virtual ICollection<Enrollment> Enrollments { get; set; }
}
Enrollmentsプロパティはナビゲーションプロパティです。 コースエンティティは、任意の数の登録エンティティに関連付けることができます。
以下は、登録クラスと列挙型の実装です。
public enum Grade {
A, B, C, D, F
}
public class Enrollment {
public int EnrollmentID { get; set; }
public int CourseID { get; set; }
public int StudentID { get; set; }
public Grade? Grade { get; set; }
public virtual Course Course { get; set; }
public virtual Student Student { get; set; }
}
- EnrollmentIDプロパティが主キーになります。
- Gradeプロパティは列挙型です。 Gradeタイプ宣言の後の疑問符は、Gradeプロパティがnull許容であることを示します。
- nullのグレードは、ゼログレードとは異なります。 Nullは、グレードが不明であるか、まだ割り当てられていないことを意味します。
- StudentIDおよびCourseIDプロパティは外部キーであり、対応するナビゲーションプロパティはStudentおよびCourseです。
- 登録エンティティは1つの学生と1つのコースエンティティに関連付けられているため、プロパティは1つの学生とコースエンティティのみを保持できます。
データベースコンテキストの作成
特定のデータモデルのEntity Framework機能を調整するメインクラスは、データのクエリと保存を可能にするデータベースコンテキストクラスです。 このクラスを作成するには、DbContextクラスから派生させ、モデル内の各クラスの型指定されたDbSetを公開します。 以下は、DbContextクラスから派生したMyContextクラスの実装です。
public class MyContext : DbContext {
public virtual DbSet<Course> Courses { get; set; }
public virtual DbSet<Enrollment> Enrollments { get; set; }
public virtual DbSet<Student> Students { get; set; }
}
以下はProgram.csファイルの完全なコードです。
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EFCodeFirstDemo {
class Program {
static void Main(string[] args) {}
}
public enum Grade {
A, B, C, D, F
}
public class Enrollment {
public int EnrollmentID { get; set; }
public int CourseID { get; set; }
public int StudentID { get; set; }
public Grade? Grade { get; set; }
public virtual Course Course { get; set; }
public virtual Student Student { get; set; }
}
public class Student {
public int ID { get; set; }
public string LastName { get; set; }
public string FirstMidName { get; set; }
public DateTime EnrollmentDate { get; set; }
public virtual ICollection<Enrollment> Enrollments { get; set; }
}
public class Course {
public int CourseID { get; set; }
public string Title { get; set; }
public int Credits { get; set; }
public virtual ICollection<Enrollment> Enrollments { get; set; }
}
public class MyContext : DbContext {
public virtual DbSet<Course> Courses { get; set; }
public virtual DbSet<Enrollment> Enrollments { get; set; }
public virtual DbSet<Student> Students { get; set; }
}
}
上記のコードは、データの保存と取得を開始するために必要なすべてです。 データを追加して取得します。 以下は、mainメソッドのコードです。
static void Main(string[] args) {
using (var context = new MyContext()) {
//Create and save a new Students
Console.WriteLine("Adding new students");
var student = new Student {
FirstMidName = "Alain", LastName = "Bomer",
EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
};
context.Students.Add(student);
var student1 = new Student {
FirstMidName = "Mark", LastName = "Upston",
EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
};
context.Students.Add(student1);
context.SaveChanges();
//Display all Students from the database
var students = (from s in context.Students
orderby s.FirstMidName select s).ToList<Student>();
Console.WriteLine("Retrieve all Students from the database:");
foreach (var stdnt in students) {
string name = stdnt.FirstMidName + " " + stdnt.LastName;
Console.WriteLine("ID: {0}, Name: {1}", stdnt.ID, name);
}
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
}
上記のコードが実行されると、次の出力が表示されます。
Adding new students
Retrieve all Students from the database:
ID: 1, Name: Alain Bomer
ID: 2, Name: Mark Upston
Press any key to exit...
ここで、頭に浮かぶ疑問は、どこにデータを追加し、データベースから取得したデータとデータベースがどこにあるかです。 慣例により、DbContextはデータベースを作成しました。
- ローカルSQL Expressインスタンスが利用可能な場合、Code Firstはそのインスタンス上にデータベースを作成しました。
- SQL Expressが利用できない場合、Code FirstはLocalDbを使用しようとします。
- データベースには、派生コンテキストの完全修飾名にちなんで名前が付けられます。
この例では、SQL Expressインスタンスが使用可能であり、データベース名は次の画像に示すようにEFCodeFirstDemo.MyContextです。
- これらはデフォルトの規則に過ぎず、Code Firstが使用するデータベースを変更するにはさまざまな方法があります。
- 上の画像でわかるように、Student、Courses、およびEnrollmentsテーブルが作成され、各テーブルには適切なデータ型と長さの列が含まれています。
- 列名とデータ型は、それぞれのドメインクラスのプロパティとも一致します。
データベースの初期化
上記の例では、Code Firstがデータベースを自動的に作成することを確認しましたが、データベースとサーバーの名前を変更する場合は、Code Firstがデータベースの初期化中にデータベース名とサーバーを決定する方法を見てみましょう。 次の図をご覧ください。
次の方法で、コンテキストクラスの基本コンストラクタを定義できます。
- パラメータなし
- データベース名
- 接続文字列名
パラメータなし
上記の例に示すように、パラメーターなしでコンテキストクラスのベースコンストラクターを指定すると、エンティティフレームワークは、ローカルSQLEXPRESSサーバーに\ {Namespace}。\ {Context class name}という名前でデータベースを作成します。
上記の例では、自動的に作成されるデータベースの名前はEFCodeFirstDemo.MyContextです。 名前を見ると、次のコードに示すように、EFCodeFirstDemoがネームスペースであり、MyContextがコンテキストクラス名であることがわかります。
public class MyContext : DbContext {
public MyContext() : base() {}
public virtual DbSet<Course> Courses { get; set; }
public virtual DbSet<Enrollment> Enrollments { get; set; }
public virtual DbSet<Student> Students { get; set; }
}
データベース名
データベース名をパラメーターとしてコンテキストクラスの基本コンストラクターに渡すと、Code Firstは自動的にデータベースを自動的に作成しますが、今回はローカルSQLEXPRESSデータベースサーバーの基本コンストラクターにパラメーターとして渡された名前になります。
次のコードでは、MyContextDBがベースコンストラクターのパラメーターとして指定されています。 アプリケーションを実行すると、MyContextDB名のデータベースがローカルSQLサーバーに作成されます。
public class MyContext : DbContext {
public MyContext() : base("MyContextDB") {}
public virtual DbSet<Course> Courses { get; set; }
public virtual DbSet<Enrollment> Enrollments { get; set; }
public virtual DbSet<Student> Students { get; set; }
}
接続文字列名
これは、SQL ExpressまたはLocalDb以外のデータベースサーバーを使用するようDbContextに指示する簡単な方法です。 app.configファイルに接続文字列を挿入することもできます。
- 接続文字列の名前がコンテキストの名前と一致する場合(名前空間修飾の有無にかかわらず)、パラメーターなしコンストラクターが使用されると、DbContextによって検出されます。
- 接続文字列名がコンテキストの名前と異なる場合、接続文字列名をDbContextコンストラクターに渡すことにより、DbContextにこの接続をCode Firstモードで使用するように指示できます。
public class MyContext : DbContext {
public MyContext() : base("name = MyContextDB") {}
public virtual DbSet<Course> Courses { get; set; }
public virtual DbSet<Enrollment> Enrollments { get; set; }
public virtual DbSet<Student> Students { get; set; }
}
- 上記のコードでは、コンテキストクラス接続文字列のスニペットが、ベースコンストラクターのパラメーターとして指定されています。
- 接続文字列名は「name =」で始まる必要があります。それ以外の場合、データベース名と見なされます。
- この形式により、接続文字列が設定ファイルで見つかることを明示的に示します。 指定された名前の接続文字列が見つからない場合、例外がスローされます。
<connectionStrings>
<add name = "MyContextDB"
connectionString = "Data Source =.;Initial Catalog = EFMyContextDB;Integrated Security = true"
providerName = "System.Data.SqlClient"/>
</connectionStrings>
- app.configの接続文字列のデータベース名は EFMyContextDB です。 CodeFirstは、新しい EFMyContextDB データベースを作成するか、ローカルSQL Serverにある既存の EFMyContextDB データベースを使用します。
ドメインクラス
これまでは、EFにデフォルトの規則を使用してモデルを検出させるだけでしたが、クラスが規則に従っていない場合があり、さらに設定を実行できるようにする必要があります。 ただし、EFに必要な情報を提供するようにドメインクラスを構成することにより、これらの規則をオーバーライドできます。 ドメインクラスを構成するには2つのオプションがあります-
- データ注釈
- 流暢なAPI
データ注釈
DataAnnotationsは、最も一般的に必要な構成を強調表示するクラスを構成するために使用されます。 DataAnnotationsは、ASP.NET MVCなどの多くの.NETアプリケーションでも理解されます。これにより、これらのアプリケーションは、クライアント側の検証に同じ注釈を活用できます。
以下は、学生クラスで使用されるデータ注釈です。
public class Enrollment {
[Key]
public int EnrollmentID { get; set; }
public int CourseID { get; set; }
public int StudentID { get; set; }
public Grade? Grade { get; set; }
[ForeignKey("CourseID")]
public virtual Course Course { get; set; }
[ForeignKey("ID")]
public virtual Student Student { get; set; }
}
流暢なAPI
ほとんどのモデル構成は、単純なデータ注釈を使用して実行できます。 Fluent APIは、データ注釈では不可能な、より高度な構成に加えて、データ注釈で可能なすべてをカバーするモデル構成を指定する高度な方法です。 データ注釈と流れるようなAPIを一緒に使用できます。
Fluent APIにアクセスするには、DbContextのOnModelCreatingメソッドをオーバーライドします。 次のコードに示すように、学生テーブルの列名をFirstMidNameからFirstNameに変更します。
public class MyContext : DbContext {
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
modelBuilder.Entity<Student>().Property(s ⇒ s.FirstMidName)
.HasColumnName("FirstName");
}
public virtual DbSet<Course> Courses { get; set; }
public virtual DbSet<Enrollment> Enrollments { get; set; }
public virtual DbSet<Student> Students { get; set; }
}