今回は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>それでは今回はこの辺で…。次回は課題である結合したデータをビューに渡したり、それを利用して更新したりする予定です。
