今回はCodeFirstでデータベースを準備します。さて早速ひとつ問題が…。MVC上のModelとEntityFramework上のModelを同一視しても良いものか?当然ながら連携面を考えた場合、同一のModelとして扱ってしまった方が楽なのは間違いなりませんし、チャートリアル等でもそのように扱われています。じゃあそうりゃいいじゃんって話なんですが、個人的にMVCとEntityFrameworkのどちらからしか使わない可能性のあるModelを作ることに抵抗があったりするわけで…。とりあえず今回はプロジェクトのModelsフォルダにDbフォルダを設け、EntityFrameworkのModelはそちらに書くことにします。
さっそくModelの定義です。
社員テーブル
using System.ComponentModel.DataAnnotations; namespace MVCTestProject.Models.Db { /// <summary> /// 社員テーブル /// </summary> public class Employee { /// <summary> /// ID /// </summary> public int EmployeeId { get; set; } /// <summary> /// 社員名 /// </summary> [MaxLength(50)] public string EmployeeName { get; set; } /// <summary> /// 配属先ID /// </summary> public int AssignId { get; set; } /// <summary> /// ソート順 /// </summary> public decimal SortNumber { get; set; } } }
配属先テーブル
using System.ComponentModel.DataAnnotations; namespace MVCTestProject.Models.Db { /// <summary> /// 配属先テーブル /// </summary> public class Assign { /// <summary> /// ID /// </summary> public int AssignId { get; set; } /// <summary> /// 配属先名 /// </summary> [MaxLength(50)] public string AssignName { get; set; } } }
コンテキスト
using System.Data.Entity; using MVCTestProject.Models.Db; namespace MVCTestProject { /// <summary> /// データベースコンテキスト /// </summary> public class MvcTestContext : DbContext { /// <summary> /// MvcTestDbという名前でDbを作成 /// </summary> public MvcTestContext() : base("MvcTestDb") { } public DbSet<Employee> Employees { get; set; } public DbSet<Assign> Assigns { get; set; } } }
データベースはとりあえずローカルに置くのでWeb.configは放置。変更が必要であればConnectionStringsタブなりEntityFrameworkタブなりに追記してください。
あと、テストデータを用意したいのでConfigurationクラスを追加します。分からなければこの辺を参照してください。
ConfigurationクラスのSeedメソッド
protected override void Seed(MVCTestProject.MvcTestContext context) { var employeeList = new List<Employee>(); Parallel.For(0, 101, (n) => { employeeList.Add(new Employee { EmployeeName = (n % 2 != 0 ? n + "男" : n + "子"), AssignId = (n % 2 != 0 ? 1 : 2), SortNumber = n }); }); var target = employeeList.ToArray(); context.Employees.AddOrUpdate(target); context.Assigns.AddOrUpdate( new Assign { AssignName = "A" }, new Assign { AssignName = "B" }); }
Emloyee型のリストを作成した後、わざわざ変数に突っ込んでるのは実行時にAddOrUpdateメソッドに「非静的メソッドはターゲットがうんぬん」と叱られるからです。これで下準備が完成です。
今後、自力でビューを作っていくにあたってMVCがデータベースに対してどうゆう動作をするか知りたいと思います。なのでとりあえずコントローラーの作成時にEntityFrameworkと連携したテンプレートを選択してみます。
テンプレートやらモデル等を選択
作成されたコントローラー
using System; using System.Collections.Generic; using System.Data; using System.Data.Entity; using System.Linq; using System.Web; using System.Web.Mvc; using MVCTestProject.Models.Db; namespace MVCTestProject.Controllers { public class EmployeeController : Controller { private MvcTestContext db = new MvcTestContext(); // // GET: /Employee/ public ActionResult Index() { return View(db.Employees.ToList()); } // // GET: /Employee/Details/5 public ActionResult Details(int id = 0) { Employee employee = db.Employees.Find(id); if (employee == null) { return HttpNotFound(); } return View(employee); } // // GET: /Employee/Create public ActionResult Create() { return View(); } // // POST: /Employee/Create [HttpPost] public ActionResult Create(Employee employee) { if (ModelState.IsValid) { db.Employees.Add(employee); db.SaveChanges(); return RedirectToAction("Index"); } return View(employee); } // // GET: /Employee/Edit/5 public ActionResult Edit(int id = 0) { Employee employee = db.Employees.Find(id); if (employee == null) { return HttpNotFound(); } return View(employee); } // // POST: /Employee/Edit/5 [HttpPost] public ActionResult Edit(Employee employee) { if (ModelState.IsValid) { db.Entry(employee).State = EntityState.Modified; db.SaveChanges(); return RedirectToAction("Index"); } return View(employee); } // // GET: /Employee/Delete/5 public ActionResult Delete(int id = 0) { Employee employee = db.Employees.Find(id); if (employee == null) { return HttpNotFound(); } return View(employee); } // // POST: /Employee/Delete/5 [HttpPost, ActionName("Delete")] public ActionResult DeleteConfirmed(int id) { Employee employee = db.Employees.Find(id); db.Employees.Remove(employee); db.SaveChanges(); return RedirectToAction("Index"); } protected override void Dispose(bool disposing) { db.Dispose(); base.Dispose(disposing); } } }
あー、なんだか長くなっちゃいましたが、何となくはデータベースに対するアクセスの仕方が見えたのではないでしょうか?データベース→データ取得→ビューに渡すって単純な流れですね。
一応、ビュー側も載せておきます。Razorは慣れないと違和感ありまくりですね。
Index.cshtml
@model IEnumerable<MVCTestProject.Models.Db.Employee> @{ ViewBag.Title = "Index"; } <h2>Index</h2> <p> @Html.ActionLink("Create New", "Create") </p> <table> <tr> <th> @Html.DisplayNameFor(model => model.EmployeeName) </th> <th> @Html.DisplayNameFor(model => model.AssignId) </th> <th> @Html.DisplayNameFor(model => model.SortNumber) </th> <th></th> </tr> @foreach (var item in Model) { <tr> <td> @Html.DisplayFor(modelItem => item.EmployeeName) </td> <td> @Html.DisplayFor(modelItem => item.AssignId) </td> <td> @Html.DisplayFor(modelItem => item.SortNumber) </td> <td> @Html.ActionLink("Edit", "Edit", new { id=item.EmployeeId }) | @Html.ActionLink("Details", "Details", new { id=item.EmployeeId }) | @Html.ActionLink("Delete", "Delete", new { id=item.EmployeeId }) </td> </tr> } </table>
それでは今回はこの辺で…。次回は課題である結合したデータをビューに渡したり、それを利用して更新したりする予定です。