ず〜〜〜〜〜っと静観してたEntity FrameworkのCode Firstですが、実はひそかにイケてる子だとずっと信じてました。今回、あるきっかけがあったので試してみました!
あるきっかけと言うのは、Web Platform InstallerでASP.NET MVC3をインストールしたついでに入ってきたNuGetのことです。
NuGetは簡単に言うと、JavaでいうMavenや、RubyでいうGemや、PerlでいうCPANみたいな感じで外部のライブラリを手軽にダウンロードして使えるように設定してくれる嬉しいやつです。(Mavenはビルドシステムだからライブラリの依存関係見てくれるだけじゃないけど)
インストールすると、Visual Studioのツールメニューに以下のような感じで追加されます。コマンドライン強者はコンソール使えばいいと思うけど、私はGUIラブなCUI弱者なのでAdd Library Package Referenceを愛用しそうです。
検索もできて、ダウンロードもしてくれて、参照も追加してくれる。至れり尽くせりです。
本題のCodeFirst
ということで、早速CodeFirstを試してみようと思います。今回は、超簡単なデータでCRUDするところまでやってみます。因みにDBはSQL Server 2008 Express Editionを使用してます。
ということで早速プロジェクトを作成します。簡単に試すだけなのでConsoleApplicationを新規作成します。プロジェクト名は「HelloCodeFirst」にしました。
ツールメニューからLibrary Package Manager → Add Library Package Referenceを選びます。Onlineを選択してCodeFirstで検索すると検索結果に目当てのブツが表示されます。
Installボタンをぽちっとすると、勝手にダウンロードからインストールまでしてくれます。
因みに、ここでインストールとしたライブラリはソリューションフォルダのpackagesというフォルダに追加されます。
あと、ちょっと残念なのですが手動でSystem.Data.Entityを参照追加して準備完了です。
エンテティの定義
さて、ここからがコードファーストの素敵な所です。DBの定義?そんなの知ったこっちゃありません!コード書いちゃいましょう。ということで、以下のようなコードを書きます。一般的な従業員と部署の関係ですね。
namespace HelloCodeFirst { using System.Collections.Generic; public class Employee { public int ID { get; set; } public string Name { get; set; } public virtual ICollection<Department> Departments { get; set; } } public class Department { public int ID { get; set; } public string Name { get; set; } public virtual Employee Employee { get; set; } } }
これでOKです。気を付ける所は、主キーが〜IDとかいう名前じゃないといけない(ほかにもOKな名前あったと思うけど忘れた後で調べよう)とか、複数のエンテティ間の関連を表すプロパティ(ここでいうEmployeeのDepartmentsプロパティや、DepartmentのEmployeeプロパティ)は、virtualじゃないといけないという所です。
これさえ気を付ければエンテティの定義は普通のクラス定義と変わりありません。
Contextの定義
さて次はContextを作っていきます。これもコードでシンプルにさっくり作ります。こいつは、System.Data.Entity.DbContextを継承して、さっき定義した型を扱うためのプロパティをSystem.Data.Entity.IDbSet
namespace HelloCodeFirst { using System.Data.Entity; public class EduContext : DbContext { public IDbSet<Employee> Employees { get; set; } public IDbSet<Department> Departments { get; set; } } }
さっそくCRUDしてみよう
ということで、さくっとCRUDする簡単なサンプルをMainメソッドに書きます。
namespace HelloCodeFirst { using System; using System.Data.Entity.Database; using System.Linq; using System.Data.Entity; class Program { static void Main(string[] args) { int deptId; using (var ctx = new EduContext()) { // Create { var dept = ctx.Departments.Create(); dept.Name = "人事課"; // Addを忘れずに ctx.Departments.Add(dept); var emp = ctx.Employees.Create(); emp.Name = "田中 太郎"; // Addを忘れずに ctx.Employees.Add(emp); emp.Department = dept; // SaveChangesで変更をDBに反映 ctx.SaveChanges(); // IDは自動生成されるので生成されたIDをとっておく deptId = dept.ID; } // Read { // LINQでとってこれる foreach (var dept in ctx.Departments.Where(d => d.ID == deptId)) { Console.WriteLine(dept.Name); foreach (var emp in dept.Employees) { Console.WriteLine(emp.Name); } } } // Update { var emp = ctx.Employees.First(); emp.Name = "木村 花子"; // SaveChangesで変更をDBに反映 ctx.SaveChanges(); // 更新結果を確認 Console.WriteLine(ctx.Employees.First().Name); } // Delete { // 作った部署をRemoveで消す var dept = ctx.Departments.First(d => d.ID = deptId); ctx.Departments.Remove(dept); var emp = ctx.Employees.First(); ctx.Employees.Remove(emp); // SaveChangesで変更をDBに反映 ctx.SaveChanges(); } } } } }
ちょっと長いですが、純粋にコレクションの操作や今までのEntityFrameworkにあったSaveChangesを呼んでるのと同じです。
実行結果は以下のようになります。
きちんと読み取ったデータも表示されてるし、更新した結果も表示されています。