データベースの準備
それでは、本題となるデータベースのクエリ処理に入るにあたり、データベースを準備します。今回はEntity Framework Code Firstを使います。Entity Framework Code Firstとは、データベースアクセスのためのフレームワークで、データベースのテーブルやフィールドをC#のクラスやプロパティとして定義し、そのクラスに対する操作を行うことで、ソースコード中にSQLを直接埋め込むことなく、データベース操作を行えるフレームワークです。詳細については前述の解説記事をご覧ください。
今回は、図2のような、商品(Products)、出荷元(Makers)、担当者(Employees)、部署(Departments)の4つのテーブルを使います。また、初期データもソースコードから投入します。
まず、Visual Studio 2013を起動して新しいプロジェクトを作成し[Windows デスクトップ]‐[コンソール アプリケーション]を選択します。次いで[プロジェクト]‐[新しい項目の追加]より[ADO.NET Entity Data Model]を追加しましょう。名前は[CodeZineSampleContext]とします(図3)。
続いて、モデルの種類として[空のCode Firstモデル]を指定します(図4)。
エンティティの定義
プロジェクトにCodeZineSampleContext.csが追加されます。まず、使用するテーブルを定義しましょう。Entity Framework Code Firstでは、ソースコードとデータベースが表1のように綺麗に対応しています。
ソースコード | データベース | 備考 |
---|---|---|
クラス定義 | テーブル定義 | テーブルに対応するクラスはエンティティと呼ばれる |
エンティティのインスタンス | テーブルの1レコード | ‐ |
数値、文字列、日時などの基本型プロパティ | テーブルのフィールド | C#のデータ型に対応するデータベースのデータ型が使用される |
他のエンティティ型のプロパティ | 関連するテーブルへのリレーション | ナビゲーションプロパティと呼ばれる特殊なプロパティ。ICollectionを使うと1対多関係となる。virtualとして宣言すると遅延ローディング(第3回で解説)が有効になる |
先ほどのER図に合わせて、リスト4のように使用するエンティティの定義を追加します。ここでは、今回使用する商品、担当者、部署、出荷元のエンティティを定義し、必要なフィールドをプロパティとして定義し、関連するリレーションをナビゲーションプロパティとして定義しています。
public class Product //商品 { public int Id { get; set; } //プライマリキー public string Name { get; set; } //商品名 public int Price { get; set; } //金額 public virtual Maker Maker { get; set; } //出荷元 public virtual Employee Employee { get; set; } //商品担当者 } public class Employee //担当者 { public int Id { get; set; } //プライマリキー public string Name { get; set; }//担当者名 public DateTime Birthday { get; set; }//誕生日 public virtual Department Department { get; set; } //所属部署 //担当する商品一覧。ICollectionを使って1対多関係を表現 public ICollection<Product> Products { get; set; } } public class Department //部署 { public int Id { get; set; } //プライマリキー public string Name { get; set; } //部署名 public ICollection<Employee> Employees { get; set; } //部署内担当者一覧 } public class Maker //出荷元 { public int Id { get; set; } //プライマリキー public string Name { get; set; } //会社名 public virtual ICollection<Product> Products { get; set; } //出荷商品一覧 }
コンテキストクラスの定義
また、Entity Frameworkの作法では、コンテキストクラスと呼ばれるクラスがデータベースアクセスの基本となります。コンテキストクラスにはエンティティのDbSet(=エンティティの一覧を表すクラス。データベースのテーブルに相当)を定義する必要がありますので、今回のコンテキストクラスであるCodeZineSampleContextのプロパティに定義したエンティティのDbSetを追加します(リスト5)。
public class CodeZineSampleContext : DbContext { ・・・ //コンテキストクラスのプロパティで各エンティティのDbSetを持っておく public virtual DbSet<Employee> Employees { get; set; } public virtual DbSet<Department> Departments { get; set; } public virtual DbSet<Product> Products { get; set; } public virtual DbSet<Maker> Makers { get; set; } }
データの挿入
続いて、リスト6のようなコードで、データベースにデータを挿入します。挿入方法の詳細はサンプルを参照してください。サンプルでは、クエリ対象として5個ほどの商品(Product)データと、それに関連する担当者、部署、出荷元データを挿入しています。
var department1 = new Department() //部署を作成 { Name = "営業部" }; var employee1 = new Employee() //担当者を作成 { Name = "土井", Birthday = DateTime.Parse("1978-10-25"), //(1)この担当者の部署は「営業部」 Department = department1 }; var maker1 = new Maker() //出荷元 { Name = "お菓子屋さんA" }; var product1 = new Product() //商品定義 { Name = "ショートケーキ", Price = 250, Maker = maker1, //出荷元は「お菓子屋さんA」 Employee = employee1, //担当者は「土井」 }; //商品を登録(関連するエンティティも自動的に登録される) context.Products.Add(product1); ・・・ //保存 context.SaveChanges();
ここで作成しているdepartment1、employee1、maker1、product1などはテーブルのレコードに相当し、それぞれのオブジェクトのプロパティはレコードのフィールドに相当します。また、他のテーブルへのリレーションもプロパティで指定します。
たとえば、(1)ではemployee1のDepartmentプロパティに、上で作成したdepartment1を設定しています。これは、担当者「土井」は「営業部」という部署に所属するという関係になります。実際のデータベース上では、EmployeesテーブルのDepartment_IdフィールドにDepeartmentsテーブルのIdフィールドの値が設定されます(図5、図6)。
まとめ
今回はLINQとラムダ式の概要を解説しました。やや特殊な記法のLINQクエリ式に比べて、メソッドを連ねていくメソッド式は比較的なじみやすいと感じられたのではないでしょうか。また、Entity Framework Code Firstを使ってクエリ対象のデータベースも準備しました。
次回は「LINQメソッド式を使ってみよう」と題して、実際にLINQメソッド式を使ったクエリについて解説します。お楽しみに。