著者: Tom Dykstra
Contoso University のサンプル Web アプリケーションでは、Entity Framework 5 Code First と Visual Studio 2012 を使用して ASP.NET MVC 4 アプリケーションを作成する方法を示します。 チュートリアル シリーズについては、シリーズの最初のチュートリアルを参照してください。
Note
解決できない問題が発生した場合は、完了した章をダウンロードして、問題を再現してみてください。 通常、コードを完成したコードと比較することで、問題の解決策を見つけることができます。 一般的なエラーとその解決方法については、「エラーと回避策」をご覧ください。
前のチュートリアルでは、Student
エンティティの基本的な CRUD 操作用の Web ページのセットを実装しました。 このチュートリアルでは、Students インデックス ページに、並べ替え、フィルター、およびページング機能を追加します。 単純なグループ化を実行するページも作成します。
次の図は、作業が終了したときにページがどのように表示されるかを示しています。 列見出しとは、ユーザーがクリックしてその列で並べ替えを行うことができるリンクです。 列見出しを繰り返しクリックすると、昇順と降順の並べ替え順序が切り替えられます。
Students インデックス ページに列の並べ替えリンクを追加する
Students インデックス ページに並べ替えを追加するには、Student
コントローラーの Index
メソッドを変更し、Student
インデックス ビューにコードを追加します。
Index メソッドに並べ替え機能を追加する
Controllers\StudentController.cs で、Index
メソッドを次のコードに置き換えます。
public ActionResult Index(string sortOrder)
{
ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "Name_desc" : "";
ViewBag.DateSortParm = sortOrder == "Date" ? "Date_desc" : "Date";
var students = from s in db.Students
select s;
switch (sortOrder)
{
case "Name_desc":
students = students.OrderByDescending(s => s.LastName);
break;
case "Date":
students = students.OrderBy(s => s.EnrollmentDate);
break;
case "Date_desc":
students = students.OrderByDescending(s => s.EnrollmentDate);
break;
default:
students = students.OrderBy(s => s.LastName);
break;
}
return View(students.ToList());
}
このコードは、URL 内の文字列から sortOrder
パラメーターを受け取ります。 クエリ文字列の値は、ASP.NET Core MVC によってパラメーターとしてアクション メソッドに提供されます。 パラメータは、"Name" または "Date" という文字列で、その後に必要に応じてアンダースコアと降順を指定する文字列 "desc" が続きます。 既定の並べ替え順序は昇順です。
インデックス ページが初めて要求されたときには、クエリ文字列はありません。 学生は、LastName
の昇順で表示されます。これは、switch
ステートメントのフォールスルー ケースによって確立される既定値です。 ユーザーが列見出しハイパーリンクをクリックすると、適切な sortOrder
値がクエリ文字列で提供されます。
ビューで適切なクエリ文字列値を使用して列見出しのハイパーリンクを構成できるように、2 つの ViewBag
変数が使用されます。
ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "Name_desc" : "";
ViewBag.DateSortParm = sortOrder == "Date" ? "Date_desc" : "Date";
これらは、三項ステートメントです。 最初のパラメーターは、sortOrder
パラメーターが null または空の場合、ViewBag.NameSortParm
は "name_desc" に設定されることを指定します。それ以外の場合は、空の文字列に設定されます。 これらの 2 つのステートメントを使用して、次のようにビューで列見出しのハイパーリンクの設定することができます。
既定の並べ替え順 | 姓のハイパーリンク | 日付のハイパーリンク |
---|---|---|
姓の昇順 | descending | ascending |
姓の降順 | ascending | ascending |
日付の昇順 | ascending | descending |
日付の降順 | ascending | ascending |
このメソッドは、LINQ to Entities を使用して、並べ替えの基準となる列を指定します。 このコードでは、switch
ステートメントの前に IQueryable 変数を作成し、それを switch
ステートメントで変更し、switch
ステートメントの後に ToList
メソッドを呼び出します。 IQueryable
変数を作成および変更するときに、データベースに送信されるクエリはありません。 このクエリは、ToList
などのメソッドを呼び出して、IQueryable
オブジェクトをコレクションに変換するまで、実行されません。 そのため、このコードの結果は、return View
ステートメントまで実行されない 1 つのクエリになります。
列見出しハイパーリンクを Student インデックス ビューに追加する
Views\Student\Index.cshtml で、見出し行の <tr>
要素と <th>
要素を強調表示されたコードに置き換えます。
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th>
@Html.ActionLink("Last Name", "Index", new { sortOrder = ViewBag.NameSortParm })
</th>
<th>First Name
</th>
<th>
@Html.ActionLink("Enrollment Date", "Index", new { sortOrder = ViewBag.DateSortParm })
</th>
<th></th>
</tr>
@foreach (var item in Model)
{
このコードは、ViewBag
プロパティ内の情報を使用して、適切なクエリ文字列を使用するハイパーリンクを設定します。
ページを実行し、[姓] 列と [登録日] 列の見出しをクリックして、並べ替えが機能することを確認します。
[姓] 見出しを クリックすると、学生は姓の降順で表示されます。
Students インデックス ページに [検索] ボックスを追加する
Students インデックス ページにフィルターを追加するには、テキスト ボックスと送信ボタンをビューに追加し、Index
メソッドで対応する変更を行います。 テキスト ボックスを使用して、姓と名のフィールドに検索する文字列を入力できます。
Index メソッドにフィルター機能を追加する
Controllers\StudentController.cs で、Index
メソッドを次のコードで置き換えます (変更部分が強調表示されています)。
public ViewResult Index(string sortOrder, string searchString)
{
ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
ViewBag.DateSortParm = sortOrder == "Date" ? "date_desc" : "Date";
var students = from s in db.Students
select s;
if (!String.IsNullOrEmpty(searchString))
{
students = students.Where(s => s.LastName.ToUpper().Contains(searchString.ToUpper())
|| s.FirstMidName.ToUpper().Contains(searchString.ToUpper()));
}
switch (sortOrder)
{
case "name_desc":
students = students.OrderByDescending(s => s.LastName);
break;
case "Date":
students = students.OrderBy(s => s.EnrollmentDate);
break;
case "date_desc":
students = students.OrderByDescending(s => s.EnrollmentDate);
break;
default:
students = students.OrderBy(s => s.LastName);
break;
}
return View(students.ToList());
}
searchString
パラメーターを Index
メソッドに追加しました。 また、LINQ ステートメントに、名または姓に検索文字列が含まれる学生のみを選択する where
句を追加しました。 検索文字列の値は、インデックス ビューに追加するテキスト ボックスから受け取ります。検索する値がある場合にのみ、where 句を追加するステートメントが実行されます。
Note
多くの場合、同じメソッドを Entity Framework エンティティ セットで呼び出すか、メモリ内コレクションの拡張メソッドとして呼び出すことができます。 結果は通常同じですが、場合によっては異なる場合があります。 たとえば、Contains
メソッドの .NET Framework 実装では、空の文字列を渡すとすべての行が返されますが、SQL Server Compact 4.0 の Entity Framework プロバイダーは空の文字列に対して 0 行を返します。 したがって、この例のコード (Where
ステートメントを if
ステートメント内に配置) では、すべてのバージョンの SQL Server で確実に同じ結果が得られるようになっています。 また、Contains
メソッドの .NET Framework 実装では、既定では大文字と小文字を区別しますが、Entity Framework SQL Server プロバイダーでは既定で大文字と小文字が区別されません。 したがって、ToUpper
メソッドを呼び出してテストで明示的に大文字と小文字を区別しないようにすると、後でリポジトリを使用するようにコードを変更しても結果が変わらないようにできます。これにより、IQueryable
オブジェクトではなく IEnumerable
コレクションが返されます。 (IEnumerable
コレクションに対して Contains
メソッドを呼び出したときには、.NET Framework の実装を取得します。IQueryable
オブジェクトに対して呼び出したときには、データベース プロバイダーの実装を取得します)。
Students インデックス ビューに [Search] ボックスを追加する
Views\Student\Index.cshtml で、開き table
タグの直前に次の強調表示されたコードを追加して、キャプション、テキスト ボックス、および [Search] ボタンを作成します。
<p>
@Html.ActionLink("Create New", "Create")
</p>
@using (Html.BeginForm())
{
<p>
Find by name: @Html.TextBox("SearchString")
<input type="submit" value="Search" /></p>
}
<table>
<tr>
ページを実行し、検索文字列を入力し、[検索] をクリックしてフィルター処理が機能していることを確認します。
URL に検索文字列の "an" が含まれていないことに注意してください。つまり、このページをブックマークしても、ブックマークを使ってフィルター処理されたリストを取得することはできません。 チュートリアルの後半では、フィルター条件にクエリ文字列を使用するように [検索] ボタンを変更します。
Students インデックス ページにページングを追加する
Students インデックス ページにページングを追加するには、まず PagedList.Mvc NuGet パッケージをインストールします。 その次に、Index
メソッドに追加の変更を加え、ページング リンクを Index
ビューに追加します。 PagedList.Mvc は、ASP.NET MVC の多くの優れたページングおよび並べ替えパッケージの 1 つであり、ここでの使用は、あくまで例としてであり、他のオプションより推奨されるということではありません。 ページング リンクを次の図に示します。
PagedList.MVC NuGet パッケージをインストールする
NuGet PagedList.Mvc パッケージは、PagedList パッケージを依存関係として自動的にインストールします。 PagedList パッケージは、IQueryable
および IEnumerable
コレクションに対する PagedList
コレクションの種類と拡張メソッドをインストールします。 拡張メソッドは、IQueryable
または IEnumerable
から PagedList
コレクション内に 1 ページのデータを作成し、 PagedList
コレクションにはページングを容易にする複数のプロパティとメソッドが用意されています。 PagedList.Mvc パッケージは、ページング ボタンを表示するページング ヘルパーをインストールします。
[ツール] メニューで、[NuGet パッケージ マネージャー]、さらに [ソリューションの NuGet パッケージの管理] の順に選択します。
[NuGet パッケージの管理] ダイアログ ボックスで、左側の [オンライン] タブをクリックし、検索ボックスに「paged」と入力します。 PagedList.Mvc パッケージが表示されたら、[インストール] をクリックします。
[プロジェクトの選択] ボックスで、[OK] をクリックします。
Index メソッドにページング機能を追加する
Controllers\StudentController.csで、PagedList
名前空間の using
ステートメントを追加します。
using PagedList;
Index
メソッドを次のコードで置き換えます。
public ViewResult Index(string sortOrder, string currentFilter, string searchString, int? page)
{
ViewBag.CurrentSort = sortOrder;
ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
ViewBag.DateSortParm = sortOrder == "Date" ? "date_desc" : "Date";
if (searchString != null)
{
page = 1;
}
else
{
searchString = currentFilter;
}
ViewBag.CurrentFilter = searchString;
var students = from s in db.Students
select s;
if (!String.IsNullOrEmpty(searchString))
{
students = students.Where(s => s.LastName.ToUpper().Contains(searchString.ToUpper())
|| s.FirstMidName.ToUpper().Contains(searchString.ToUpper()));
}
switch (sortOrder)
{
case "name_desc":
students = students.OrderByDescending(s => s.LastName);
break;
case "Date":
students = students.OrderBy(s => s.EnrollmentDate);
break;
case "date_desc":
students = students.OrderByDescending(s => s.EnrollmentDate);
break;
default: // Name ascending
students = students.OrderBy(s => s.LastName);
break;
}
int pageSize = 3;
int pageNumber = (page ?? 1);
return View(students.ToPagedList(pageNumber, pageSize));
}
このコードでは、次に示すように、page
パラメーター、現在の並べ替え順序パラメーター、および現在のフィルター パラメーターをメソッド シグネチャに追加します。
public ActionResult Index(string sortOrder, string currentFilter, string searchString, int? page)
最初にページが表示されるとき、またはユーザーがページングや並べ替えのリンクをクリックしていない場合、すべてのパラメーターは null になります。 ページング リンクをクリックすると、表示するページ番号が page
変数に保持されます。
A ViewBag
プロパティは、現在の並べ替え順序でビューを提供します。ページング時に並べ替え順序を維持するには、このビューをページング リンクに含める必要があるためです。
ViewBag.CurrentSort = sortOrder;
もう 1 つのプロパティ ViewBag.CurrentFilter
は、ビューに現在のフィルター文字列を提供します。 ページング中にフィルターの設定を維持するために、ページングのリンクにこの値を含める必要があり、ページが再表示されるときに、この値をテキスト ボックスに復元する必要があります。 ページングの中に検索文字列を変更した場合は、新しいフィルターのために別のデータが表示されるため、ページを 1 にリセットする必要があります。 テキスト ボックスに値を入力して、[Submit] ボタンを押したときに、検索文字列が変更されます。 その場合は、searchString
パラメーターは null ではありません。
if (searchString != null)
page = 1;
else
searchString = currentFilter;
メソッドの最後に、学生 IQueryable
オブジェクトの ToPagedList
拡張メソッドは、学生クエリを、ページングをサポートするコレクション型の学生の単一ページに変換します。 そして、この学生の単一ページがビューに渡されます。
int pageSize = 3;
int pageNumber = (page ?? 1);
return View(students.ToPagedList(pageNumber, pageSize));
ToPagedList
メソッドは、ページ番号を受け取ります。 2 つの疑問符は、null 合体演算子を表します。 null 合体演算子は null 許容型の既定値を定義します。式 (page ?? 1)
は、値がある場合は page
の値を返し、page
が null の場合は 1 を返すことを意味します。
Student インデックス ビューにページングのリンクを追加する
Views\Student\Index.cshtml で、既存のコードを次のコードに置き換えます。
@model PagedList.IPagedList<ContosoUniversity.Models.Student>
@using PagedList.Mvc;
<link href="~/Content/PagedList.css" rel="stylesheet" type="text/css" />
@{
ViewBag.Title = "Students";
}
<h2>Students</h2>
<p>
@Html.ActionLink("Create New", "Create")
</p>
@using (Html.BeginForm("Index", "Student", FormMethod.Get))
{
<p>
Find by name: @Html.TextBox("SearchString", ViewBag.CurrentFilter as string)
<input type="submit" value="Search" />
</p>
}
<table>
<tr>
<th></th>
<th>
@Html.ActionLink("Last Name", "Index", new { sortOrder=ViewBag.NameSortParm, currentFilter=ViewBag.CurrentFilter })
</th>
<th>
First Name
</th>
<th>
@Html.ActionLink("Enrollment Date", "Index", new { sortOrder = ViewBag.DateSortParm, currentFilter = ViewBag.CurrentFilter })
</th>
</tr>
@foreach (var item in Model) {
<tr>
<td>
@Html.ActionLink("Edit", "Edit", new { id=item.StudentID }) |
@Html.ActionLink("Details", "Details", new { id=item.StudentID }) |
@Html.ActionLink("Delete", "Delete", new { id=item.StudentID })
</td>
<td>
@Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
@Html.DisplayFor(modelItem => item.FirstMidName)
</td>
<td>
@Html.DisplayFor(modelItem => item.EnrollmentDate)
</td>
</tr>
}
</table>
<br />
Page @(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of @Model.PageCount
@Html.PagedListPager( Model, page => Url.Action("Index", new { page, sortOrder = ViewBag.CurrentSort, currentFilter=ViewBag.CurrentFilter }) )
ページの上部にある @model
ステートメントは、ビューが List
オブジェクトの代わりに PagedList
オブジェクトを取得するようになったことを指定します。
PagedList.Mvc
で using
ステートメントを使用することで、ページング ボタンの MVC ヘルパーにアクセスできます。
このコードでは、BeginForm のオーバーロードを使用することで、FormMethod.Get を指定できます。
@using (Html.BeginForm("Index", "Student", FormMethod.Get))
{
<p>
Find by name: @Html.TextBox("SearchString", ViewBag.CurrentFilter as string)
<input type="submit" value="Search" />
</p>
}
既定の BeginForm は、POST を使用してフォーム データを送信します。これは、パラメーターが、URL 内のクエリ文字列として渡されるのではなく、HTTP メッセージの本文で渡されることを意味します。 HTTP GET を指定すると、フォーム データがクエリ文字列として URL で渡され、ユーザーが URL をブックマークできるようになります。 HTTP GET の使用に関する W3C ガイドラインでは、アクションの結果が更新ではない場合は GET を使用する必要があることを指定します。
テキスト ボックスは現在の検索文字列で初期化されるため、新しいページをクリックすると、現在の検索文字列が表示されます。
Find by name: @Html.TextBox("SearchString", ViewBag.CurrentFilter as string)
列ヘッダーへのリンクは、フィルターの結果内でユーザーが並べ替えられるように、クエリ文字列を使用してコントローラーに現在の検索文字列を渡します。
@Html.ActionLink("Last Name", "Index", new { sortOrder=ViewBag.NameSortParm, currentFilter=ViewBag.CurrentFilter })
現在のページとページの合計数が表示されます。
Page @(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of @Model.PageCount
表示するページがない場合は、"Page 0 of 0" が表示されます。 (その場合、Model.PageNumber
は 1 で、Model.PageCount
は 0 であるため、ページ番号はページ数より大きくなります。)
ページング ボタンは、PagedListPager
ヘルパーによって表示されます。
@Html.PagedListPager( Model, page => Url.Action("Index", new { page }) )
PagedListPager
ヘルパーには、URL やスタイル設定など、カスタマイズできるさまざまなオプションが用意されています。 詳細については、GitHub サイト TroyGoode/PagedList を参照してください。
このページを実行します。
異なる並べ替え順でページングのリンクをクリックし、ページングが機能することを確認します。 その後で、検索文字列を入力して、ページングをもう一度試し、並べ替えとフィルター処理を使用してもページングが正しく機能することを確認します。
受講者の統計情報を表示する [About] ページを作成する
Contoso 大学の Web サイトの [About] ページに、登録日付ごとに登録した受講者の数が表示されます。 これには、グループ化とグループに関する簡単な計算が必要です。 これを実行するためには、次の手順を実行します。
- ビューに渡す必要があるデータのビュー モデル クラスを作成します。
Home
コントローラーのAbout
メソッドを変更します。About
ビューを変更します。
ビュー モデルの作成
ViewModels フォルダーを作成します。 そのフォルダー内に、EnrollmentDateGroup.cs という名前のクラス ファイルを追加し、既存のコードを次のコードに置き換えます。
using System;
using System.ComponentModel.DataAnnotations;
namespace ContosoUniversity.ViewModels
{
public class EnrollmentDateGroup
{
[DataType(DataType.Date)]
public DateTime? EnrollmentDate { get; set; }
public int StudentCount { get; set; }
}
}
Home コントローラーを変更する
HomeController.cs で、ファイルの先頭に次の using
ステートメントを追加します。
using ContosoUniversity.DAL;
using ContosoUniversity.ViewModels;
クラスの開き中かっこの直後に、データベース コンテキストのクラス変数を追加します。
public class HomeController : Controller
{
private SchoolContext db = new SchoolContext();
About
メソッドを次のコードで置き換えます。
public ActionResult About()
{
var data = from student in db.Students
group student by student.EnrollmentDate into dateGroup
select new EnrollmentDateGroup()
{
EnrollmentDate = dateGroup.Key,
StudentCount = dateGroup.Count()
};
return View(data);
}
LINQ ステートメントは、登録日で受講者エンティティをグループ化し、各グループ内のエンティティの数を計算して、結果を EnrollmentDateGroup
ビュー モデル オブジェクトのコレクションに格納します。
Dispose
メソッドを追加します。
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
About ビューを変更する
Views\Home\About.cshtml ファイルのコードを次のコードに置き換えます。
@model IEnumerable<ContosoUniversity.ViewModels.EnrollmentDateGroup>
@{
ViewBag.Title = "Student Body Statistics";
}
<h2>Student Body Statistics</h2>
<table>
<tr>
<th>
Enrollment Date
</th>
<th>
Students
</th>
</tr>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.EnrollmentDate)
</td>
<td>
@item.StudentCount
</td>
</tr>
}
</table>
アプリを実行し、[バージョン情報] リンクをクリックします。 登録の日付ごとの学生の数が、テーブルに表示されます。
省略可能: Windows Azure にアプリをデプロイする
これまで、アプリケーションは開発用コンピューター上の IIS Express でローカルに実行されていました。 他のユーザーがインターネット経由で使用できるようにするには、Web ホスティング プロバイダーにデプロイする必要があります。 チュートリアルのこの省略可能なセクションでは、これを Windows Azure Web サイトにデプロイします。
Code First Migrations を使用してデータベースをデプロイする
データベースをデプロイするには、Code First Migrations を使用します。 Visual Studio からデプロイするための設定を構成するのに使用する発行プロファイルの作成時に、[Code First Migrations の実行 (アプリケーションの起動時に実行)] というラベルの付いたチェック ボックスをオンにします。 この設定により、デプロイ プロセスは、Code First が MigrateDatabaseToLatestVersion
初期化子クラスを使用するように、移行先サーバー上のアプリケーション Web.config ファイルを自動的に構成します。
Visual Studio は、デプロイ プロセス中、データベースに対して何も行いません。 デプロイされたアプリケーションがデプロイ後に初めてデータベースにアクセスすると、Code First は、データベースを自動的に作成するか、データベース スキーマを最新バージョンに更新します。 アプリケーションで Migrations Seed
メソッドが実装されている場合、データベースの作成後またはスキーマの更新後にこのメソッドが実行されます。
Migrations Seed
メソッドはテスト データを挿入します。 運用環境にデプロイする場合は、運用データベースに挿入するデータのみを挿入するように、Seed
メソッドを変更する必要があります。 たとえば、現在のデータ モデルでは、実際の授業に対し架空の学生を開発データベースに含めたい場合があります。 開発中には両方を読み込むよう Seed
メソッドを記述し、運用環境にデプロイする前に架空の学生をコメントアウトできます。 または、Seed
メソッドを記述して授業のみを読み込み、アプリケーションの UI を使用してテスト データベースに架空の学生を手動で入力することもできます。
Windows Azure アカウントを取得する
Windows Azure アカウントが必要です。 まだアカウントがない場合は、ほんの数分で無料評価版のアカウントを作成できます。 詳細については、「Windows Azure 無料評価版」を参照してください。
Windows Azure で Web サイトと SQL データベースを作成する
Windows Azure Web サイトは共有ホスティング環境で実行されます。つまり、他の Windows Azure クライアントと共有されている仮想マシン (VM) 上で実行されます。 共有ホスティング環境は、低コストでクラウドの利用を開始できる方法です。 後で Web トラフィックが増加したら、アプリケーションの規模を変更して専用 VM 上で実行するように設定してニーズを満たすことができます。 より複雑なアーキテクチャが必要な場合は、Windows Azure クラウド サービスに移行できます。 クラウド サービスは専用 VM 上で実行され、ユーザーのニーズに応じて構成できます。
Windows Azure SQL Database は、SQL Server テクノロジに基づいて構築されたクラウドベースのリレーショナル データベース サービスです。 SQL Server で動作するツールおよびアプリケーションは、SQL Database でも動作します。
Windows Azure の管理ポータルで、左側のタブにある [Web サイト] をクリックし、[新規] をクリックします。
[カスタム作成]をクリックします。
[新しい Web サイト - カスタム作成] ウィザードが開きます。
ウィザードの [新しい Web サイト] ステップで、[URL] ボックスに、アプリケーションの 一意の URL として使用する文字列を入力します。 ここに入力した文字列と、このテキスト ボックスの右側に表示されている文字列を組み合わせたものが実際の URL になります。 この図では "ConU" と表示されていますが、この URL はおそらく取得済みのため、別の URL を選択する必要があります。
[リージョン] ドロップダウン リストで、近くのリージョンを選択します。 この設定によって、使用する Web サイトが実行されるデータ センターが指定されます。
[データベース ] ドロップダウン リストで、[無料の 20 MB SQL データベース の作成] を選択します。
DB 接続文字列名 に、「SchoolContext」と入力します。
ボックスの下部にある右矢印をクリックします。 ウィザードが [データベース設定] ステップに進みます。
[名前] ボックスに「ContosoUniversityDB」と入力します。
[サーバー] ボックスで、[新しい SQL Database サーバー] を選択します。 または、以前にサーバーを作成した場合は、ドロップダウン リストからそのサーバーを選択できます。
管理者のログイン名とパスワードを入力します。 [新しい SQL Database サーバー] を選択した場合は、既存の名前とパスワードではなく、このデータベースへのアクセス時に使用する新しい名前とパスワードを入力してください。 以前に作成したサーバーを選択した場合は、そのサーバーの資格情報を入力します。 このチュートリアルでは、 [詳細] チェック ボックスはオンにしません。 [詳細] オプションを使用すると、データベースの照合順序を設定できます。
[リージョン] では、クラウド サービスに選択したリージョンと同じリージョンを選択します。
終了したら、ダイアログ ボックスの右下にあるチェック マークをクリックします。
次の画像では、既存の SQL Server を選択した場合のログインを示しています。
管理ポータルが [Web サイト] ページに戻り、[状態] 列にサイトが作成されていることが表示されます。 しばらくすると (通常は 1 分未満)、サイトの作成に成功したことが [状態] 列に示されます。 左側のナビゲーション バーで、アカウントに含まれているサイトの数が [Web サイト] アイコンの横に表示され、[SQL データベース] アイコンの横にデータベースの数が表示されます。
Azureにアプリケーションをデプロイする
Visual Studio のソリューション エクスプローラーで、プロジェクトを右クリックし、コンテキスト メニューの [発行] をクリックします。
Web の発行ウィザードの [プロファイル] タブで、[インポート] をクリックします。
Visual Studio で Windows Azure サブスクリプションを追加していない場合は、次の手順を実行します。 これらの手順では、お使いのサブスクリプションを追加して、[Windows Azure Web サイトからのインポート] のドロップダウン リストに Web サイトが含まれるようにします。
a. [発行プロファイルのインポート] ダイアログ ボックスで、[Windows Azure Web サイトからインポート] をクリックし、[Windows Azure サブスクリプションの追加] をクリックします。
b. [Windows Azure サブスクリプションのインポート] ダイアログ ボックスで、[サブスクリプション ファイルのダウンロード] をクリックします。
c. ブラウザー ウィンドウで、.publishsettings ファイルを保存します。
警告
セキュリティについて - publishsettings ファイルには、Azure のサブスクリプションおよびサービスを管理するために使用される (エンコードされていない) 資格情報が保存されています。 このファイルのセキュリティのベスト プラクティスは、それをソース ディレクトリの外部 (Libraries\Documents フォルダーなど) に一時的に保存し、インポートが完了したら削除することです。 悪意のあるユーザーが
.publishsettings
ファイルへのアクセスを得ると、Azure サービスの編集、作成、削除が可能になるためです。d. [Windows Azure サブスクリプションのインポート] ダイアログ ボックスで、[参照] をクリックし、.publishsettings ファイルに移動します。
e. [インポート] をクリックします。
[発行プロファイルのインポート] ダイアログ ボックスで、[Windows Azure Web サイトからインポート] を選択し、ドロップダウン リストから Web サイトを選択して、[OK] をクリックします。
[接続] タブで、[接続の検証] をクリックして、設定が正しいことを確認します。
接続が検証されると、[接続の検証] ボタンの横に緑色のチェック マークが表示されます。 次へ をクリックします。
SchoolContext の下にある [リモート接続文字列] ドロップダウン リストを開き、作成したデータベースの接続文字列を選択します。
[Code First Migrations の実行 (アプリケーションの起動時に実行)] を選択します。
このアプリケーションはメンバーシップ データベースを使用していないため、[UserContext (DefaultConnection)] について [実行時にこの接続文字列を使用する] チェック ボックスをオフにします。
次へ をクリックします。
[プレビュー] タブで、[プレビューの開始] をクリックします。
このタブに、サーバーにコピーされるファイルの一覧が表示されます。 プレビューの表示は、アプリケーションの発行に必要ではありませんが、知っておくと便利な機能です。 この場合、表示されるファイルの一覧で操作を行う必要はありません。 次にこのアプリケーションをデプロイするときは、変更されたファイルのみがこの一覧に含まれます。
[発行] をクリックします。
Visual Studio は、Windows Azure サーバーにファイルをコピーするプロセスを開始します。出力 ウィンドウでは、実行されたデプロイ操作が表示され、デプロイが問題なく完了したことが報告されます。
デプロイが成功すると、自動的に既定のブラウザーが開き、デプロイ先の Web サイトの URL にアクセスします。
これで、作成したアプリケーションはクラウドで実行されています。 [学生] タブをクリックします。
この時点で、SchoolContext データベースが Windows Azure SQL Database に作成されました。これは、[Code First Migrations の実行 (アプリケーションの起動時に実行)]を選択したためです。 デプロイされた Web サイトの Web.config ファイルが変更されいるため、コードがデータベース内のデータを初めて読み書きするときに MigrateDatabaseToLatestVersion 初期化子が実行されます (これが、[Students] タブを選択したときに発生しました)。
デプロイ プロセスでは、Code First Migrations 用の新しい接続文字列 (SchoolContext_DatabasePublish) も作成され、データベース スキーマの更新とデータベースのシード処理に使用されます。
DefaultConnection 接続文字列は、メンバーシップ データベース用です (このチュートリアルでは使用しません)。 SchoolContext 接続文字列は、ContosoUniversity データベース用です。
デプロイされたバージョンの Web.config ファイルは、自分のコンピューターの ContosoUniversity\obj\Release\Package\PackageTmp\Web.config にあります。デプロイされた Web.config ファイル自体には、FTP を使用してアクセスできます。 手順については、「Visual Studio を使用した ASP.NET Web デプロイ: コード更新プログラムのデプロイ」を参照してください。 「FTP ツールを使用するには、FTP URL、ユーザー名、パスワードの 3 つが必要です」で始まる手順に従います。
Note
Web アプリにはセキュリティが実装されていないため、URL を見つけたすべてのユーザーがデータを変更できます。 Web サイトをセキュリティで保護する方法については、「メンバーシップ、OAuth、SQL Database を使用してセキュリティで保護された ASP.NET MVC アプリを Windows Azure Web サイト にデプロイする」を参照してください。 Windows Azure 管理ポータルまたは Visual Studio のサーバー エクスプローラーを使用してサイトを停止することで、他のユーザーがサイトを使用できないようにすることができます。
Code First 初期化子
デプロイ セクションで、MigrateDatabaseToLatestVersion 初期化子が使用されていることを確認しました。 Code First には、CreateDatabaseIfNotExists (既定値)、DropCreateDatabaseIfModelChanges、DropCreateDatabaseAlways など、使用できる他の初期化子も用意されています。 DropCreateAlways
初期化子は、単体テストの条件を設定する場合に役立ちます。 独自の初期化子を記述することもできます。また、アプリケーションがデータベースに対し読み書きを行うまで待機したくない場合は、初期化子を明示的に呼び出すことができます。 初期化子の包括的な説明については、「Entity Framework のプログラミング: Code First」 (Julie Lerman と Rowan Miller 共著) の第 6 章を参照してください。
まとめ
このチュートリアルでは、データ モデルを作成し、基本的な CRUD、並べ替え、フィルター処理、ページング、およびグループ化機能を実装する方法について説明しました。 次のチュートリアルでは、データ モデルを展開して、詳細なトピックについて確認します。
他の Entity Framework リソースへのリンクは、ASP.NET データ アクセス コンテンツ マップに関するページにあります。