次の方法で共有


MVC Web アプリケーションの高度な Entity Framework シナリオ (10/10)

著者: Tom Dykstra

Contoso University のサンプル Web アプリケーションでは、Entity Framework 5 Code First と Visual Studio 2012 を使用して ASP.NET MVC 4 アプリケーションを作成する方法を示します。 チュートリアル シリーズについては、シリーズの最初のチュートリアルを参照してください。

Note

解決できない問題が発生した場合は、完了した章をダウンロードして、問題を再現してみてください。 通常、完成したコードと自分のコードを比較することで、問題の解決策を見つけることができます。 一般的なエラーとその解決方法については、「エラーと回避策」をご覧ください。

前のチュートリアルでは、リポジトリと作業単位パターンを実装しました。 このチュートリアルでは、以下のトピックを取り上げます。

  • 生の SQL クエリの実行。
  • 追跡なしのクエリの実行。
  • データベースに送信されたクエリを調べる。
  • プロキシ クラスの操作。
  • 変更の自動検出を無効にする。
  • 変更を保存するときに検証を無効にする。
  • エラーと回避策

これらのトピックのほとんどでは、既に作成したページを操作します。 生 SQL を使用して一括更新を行うには、データベース内のすべてのコースのクレジット数を更新する新しいページを作成します。

[コース クレジットの更新] の初期ページを示すスクリーンショット。数値 2 がテキスト フィールドに入力されます。

また、追跡なしのクエリを使用するには、[Department Edit]\(部門の編集\) ページに新しい検証ロジックを追加します。

Contoso University Department Edit ページと重複する管理者エラー メッセージを示すスクリーンショット。

生 SQL クエリの実行

Entity Framework Code First API には、SQL コマンドをデータベースに直接渡せるようにするメソッドが含まれています。 次のようなオプションがあります。

  • エンティティ型を返すクエリに対して DbSet.SqlQuery メソッドを使用します。 返されたオブジェクトは、DbSet オブジェクトで想定されている型である必要があります。また、追跡をオフにしない限り、オブジェクトはデータベース コンテキストによって自動的に追跡されます。 ( AsNoTracking メソッドについては、次のセクションを参照してください)。
  • エンティティではない型を返すクエリには、 Database.SqlQuery メソッドを使用します。 このメソッドを使用してエンティティ型を取得する場合でも、返されるデータはデータベース コンテキストによって追跡されません。
  • クエリ以外のコマンドには、Database.ExecuteSqlCommand を使用します。

Entity Framework を使用する利点の 1 つは、データを格納する特定のメソッドにコードを過度に接近させなくてもよい点です。 SQL クエリとコマンドが生成されるため、自分でこれらを記述する必要がなくなります。 ただし、手動で作成した特定の SQL クエリを実行する必要がある場合は、例外的なシナリオがあります。これらのメソッドを使用すると、このような例外を処理できます。

Web アプリケーションで SQL コマンドを実行する場合は常に、SQL インジェクション攻撃から自身のサイトを保護する対策を講じる必要があります。 これを行う 1 つの方法として、パラメーター化されたクエリを使用して、Web ページによって送信された文字列が SQL コマンドとして解釈できないことを確認します。 このチュートリアルでは、ユーザー入力をクエリに統合するときに、パラメーター化されたクエリを使用します。

エンティティを返すクエリの呼び出し

GenericRepository クラスで、追加のメソッドを使用して派生クラスを作成しなくても、フィルター処理と並べ替えの柔軟性を高めたいとします。 これを実現する 1 つの方法は、SQL クエリを受け入れるメソッドを追加することです。 その後、結合やサブクエリに依存する Where 句など、コントローラーで任意の種類のフィルター処理や並べ替えを指定できます。 このセクションでは、このようなメソッドを実装する方法について説明します。

GenericRepository.csに次のコードを追加して、GetWithRawSql メソッドを作成します。

public virtual IEnumerable<TEntity> GetWithRawSql(string query, params object[] parameters)
{
    return dbSet.SqlQuery(query, parameters).ToList();
}

CourseController.csで、次の例に示すように、Details メソッドから新しいメソッドを呼び出します。

public ActionResult Details(int id)
{
    var query = "SELECT * FROM Course WHERE CourseID = @p0";
    return View(unitOfWork.CourseRepository.GetWithRawSql(query, id).Single());
}

この場合は、 GetByID メソッドを使用できましたが、 GetWithRawSql メソッドを使用して、 GetWithRawSQL メソッドが動作することを確認しています。

[詳細] ページを実行して、選択クエリが機能することを確認します ([ コース タブを選択し、1 つのコースに対して Details を選択します)。

Contoso University の [詳細] ページを示すスクリーンショット。

他の種類のオブジェクトを返すクエリの呼び出し

以前に、登録日ごとの学生数を示す About ページ用に、学生の統計グリッドを作成しました。 HomeController.cs でこれを行うコードでは、LINQ を使用します。

var data = from student in db.Students
           group student by student.EnrollmentDate into dateGroup
           select new EnrollmentDateGroup()
           {
               EnrollmentDate = dateGroup.Key,
               StudentCount = dateGroup.Count()
           };

LINQ を使用するのではなく、SQL でこのデータを直接取得するコードを記述するとします。 そのためには、エンティティ オブジェクト以外のものを返すクエリを実行する必要があります。つまり、 Database.SqlQuery メソッドを使用する必要があります。

HomeController.csで、About メソッドの LINQ ステートメントを次のコードに置き換えます。

var query = "SELECT EnrollmentDate, COUNT(*) AS StudentCount "
    + "FROM Person "
    + "WHERE EnrollmentDate IS NOT NULL "
    + "GROUP BY EnrollmentDate";
var data = db.Database.SqlQuery<EnrollmentDateGroup>(query);

[About] ページを実行します。 以前に行ったのと同じデータが表示されます。

Contoso University About ページを示すスクリーンショット。

更新クエリの呼び出し

Contoso University の管理者が、すべてのコースの単位数を変更するなどの、データベースでの一括変更をする機能を求めているとします。 大学に多くのコースがある場合は、それらすべてをエンティティとして取得し、それらを個別に変更するのは非効率的です。 このセクションでは、ユーザーがすべてのコースのクレジット数を変更する要因を指定できる Web ページを実装し、SQL UPDATE ステートメントを実行して変更を行います。 Web ページは次の図のようになります。

[コース クレジットの更新] の初期ページを示すスクリーンショット。数値 2 がテキスト フィールドに入力されます。

前のチュートリアルでは、汎用リポジトリを使用して、Course コントローラー内Courseエンティティの読み取りと更新を行いました。 この一括更新操作では、汎用リポジトリにない新しいリポジトリ メソッドを作成する必要があります。 そのためには、GenericRepository クラスから派生する専用のCourseRepository クラスを作成します。

DAL フォルダーにCourseRepository.csを作成し、既存のコードを次のコードに置き換えます。

using System;
using ContosoUniversity.Models;

namespace ContosoUniversity.DAL
{
    public class CourseRepository : GenericRepository<Course>
    {
        public CourseRepository(SchoolContext context)
            : base(context)
        {
        }

        public int UpdateCourseCredits(int multiplier)
        {
            return context.Database.ExecuteSqlCommand("UPDATE Course SET Credits = Credits * {0}", multiplier);
        }

    }
}

UnitOfWork.csで、Course リポジトリの種類を GenericRepository<Course> からCourseRepository:

private CourseRepository courseRepository;
public CourseRepository CourseRepository
{
    get
    {

        if (this.courseRepository == null)
        {
            this.courseRepository = new CourseRepository(context);
        }
        return courseRepository;
    }
}

CourseController.csで、UpdateCourseCredits メソッドを追加します。

public ActionResult UpdateCourseCredits(int? multiplier)
{
    if (multiplier != null)
    {
        ViewBag.RowsAffected = unitOfWork.CourseRepository.UpdateCourseCredits(multiplier.Value);
    }
    return View();
}

このメソッドは、 HttpGetHttpPostの両方に使用されます。 HttpGet UpdateCourseCredits メソッドを実行すると、前の図に示すように、multiplier変数は null になり、ビューには空のテキスト ボックスと送信ボタンが表示されます。

Update ボタンがクリックされ、HttpPost メソッドが実行されると、multiplierテキスト ボックスに値が入力されます。 その後、このコードは、影響を受ける行の数を返すリポジトリ UpdateCourseCredits メソッドを呼び出し、その値は ViewBag オブジェクトに格納されます。 ビューは、 ViewBag オブジェクト内の影響を受ける行の数を受け取ると、次の図に示すように、テキスト ボックスと送信ボタンの代わりにその数を表示します。

Contoso University Update Course クレジットの行が影響を受けるページを示すスクリーンショット。

[コース クレジットの更新] ページの Views\Course フォルダーにビューを作成します。

[ビューの追加] ダイアログ ボックスを示すスクリーンショット。[ビュー名] テキスト フィールドに[コースクレジットの更新]が入力されます。

Views/Courses/UpdateCourseCredits.cshtml で、テンプレート コードを次のコードに置き換えます。

@model ContosoUniversity.Models.Course

@{
    ViewBag.Title = "UpdateCourseCredits";
}

<h2>Update Course Credits</h2>

@if (ViewBag.RowsAffected == null)
{
    using (Html.BeginForm())
    {
        <p>
            Enter a number to multiply every course's credits by: @Html.TextBox("multiplier")
        </p>
        <p>
            <input type="submit" value="Update" />
        </p>
    }
}
@if (ViewBag.RowsAffected != null)
{
    <p>
        Number of rows updated: @ViewBag.RowsAffected
    </p>
}
<div>
    @Html.ActionLink("Back to List", "Index")
</div>

[Courses](コース) タブを選択してから、ブラウザーのアドレス バーで URL の末尾に "/UpdateCourseCredits" を追加して (例: http://localhost:50205/Course/UpdateCourseCredits)、UpdateCourseCredits メソッドを実行します。 テキスト ボックスに数値を入力します。

テキスト フィールドに数値 2 が入力された [コース クレジットの更新] の初期ページを示すスクリーンショット。

[更新] をクリックします。 影響を受けた行の数が表示されます。

更新された行数を示す [コース クレジットの更新] ページを示すスクリーンショット。

[リストに戻る] をクリックして、単位数が変更されたコースの一覧を表示します。

[コース インデックス] ページを示すスクリーンショット。コースの一覧は、修正された単位数と共に表示されます。

生の SQL クエリの詳細については、Entity Framework チームブログの「 Raw SQL クエリ を参照してください。

追跡なしクエリ

データベース コンテキストがデータベース行を取得し、それらを表すエンティティ オブジェクトを作成すると、既定では、メモリ内のエンティティがデータベース内のエンティティと同期しているかどうかを追跡します。 メモリ内のデータはキャッシュとして機能し、エンティティを更新するときに使われます。 Web アプリケーションでは、一般にコンテキスト インスタンスの存続期間は短く (要求ごとに新しいインスタンスが作成されて破棄されます)、通常、エンティティを読み取るコンテキストはエンティティが再び使われる前に破棄されるので、多くの場合、このようなキャッシュは必要ありません。

AsNoTracking メソッドを使用して、コンテキストがクエリのエンティティ オブジェクトを追跡するかどうかを指定できます。 追跡を無効にした方がよい一般的なシナリオを以下に示します。

  • クエリは、追跡をオフにするとパフォーマンスが著しく向上する可能性がある大量のデータを取得します。
  • エンティティを更新するためにアタッチする必要があるが、それより前に別の目的で同じエンティティを取得してある場合。 エンティティはデータベース コンテキストによって既に追跡されているため、変更するエンティティをアタッチできません。 これを回避する 1 つの方法は、前のクエリで AsNoTracking オプションを使用することです。

このセクションでは、これらのシナリオの 2 つ目を示すビジネス ロジックを実装します。 具体的には、インストラクターが複数の部署の管理者になることができないというビジネス ルールを適用します。

DepartmentController.csで、EditメソッドとCreateメソッドから呼び出すことができる新しいメソッドを追加して、同じ管理者が 2 つの部門にないことを確認します。

private void ValidateOneAdministratorAssignmentPerInstructor(Department department)
{
    if (department.PersonID != null)
    {
        var duplicateDepartment = db.Departments
            .Include("Administrator")
            .Where(d => d.PersonID == department.PersonID)
            .FirstOrDefault();
        if (duplicateDepartment != null && duplicateDepartment.DepartmentID != department.DepartmentID)
        {
            var errorMessage = String.Format(
                "Instructor {0} {1} is already administrator of the {2} department.",
                duplicateDepartment.Administrator.FirstMidName,
                duplicateDepartment.Administrator.LastName,
                duplicateDepartment.Name);
            ModelState.AddModelError(string.Empty, errorMessage);
        }
    }
}

検証エラーがない場合は、HttpPost Edit メソッドのtry ブロックにコードを追加して、この新しいメソッドを呼び出します。 try ブロックは次の例のようになります。

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(
   [Bind(Include = "DepartmentID, Name, Budget, StartDate, RowVersion, PersonID")]
    Department department)
{
   try
   {
      if (ModelState.IsValid)
      {
         ValidateOneAdministratorAssignmentPerInstructor(department);
      }

      if (ModelState.IsValid)
      {
         db.Entry(department).State = EntityState.Modified;
         db.SaveChanges();
         return RedirectToAction("Index");
      }
   }
   catch (DbUpdateConcurrencyException ex)
   {
      var entry = ex.Entries.Single();
      var clientValues = (Department)entry.Entity;

[部署の編集] ページを実行し、部門の管理者を、既に別の部署の管理者であるインストラクターに変更します。 次のエラー メッセージが表示されます。

管理者の重複エラー メッセージが表示された [Department Edit]\(部署の編集\) ページを示すスクリーンショット。

ここで、Department Edit ページをもう一度実行し、今度は Budget の量を変更します。 保存をクリックすると、エラー ページが表示されます。

オブジェクト状態マネージャーのエラー メッセージが表示された [Department Edit]\(部署の編集\) ページを示すスクリーンショット。

例外エラー メッセージは "An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key." です。これは、次の一連のイベントが原因で発生しました。

  • Edit メソッドは、ValidateOneAdministratorAssignmentPerInstructor メソッドを呼び出します。このメソッドは、Kim Abercrombie を管理者として持つすべての部門を取得します。 これにより、英語部門が読み取られます。 編集中の部署であるため、エラーは報告されません。 ただし、この読み取り操作の結果として、データベースから読み取られた英語部門エンティティがデータベース コンテキストによって追跡されるようになりました。
  • Edit メソッドは、MVC モデル バインダーによって作成された英語部門エンティティにModified フラグを設定しようとしますが、コンテキストが既に英語部門のエンティティを追跡しているため、失敗します。

この問題の解決策の 1 つは、コンテキストが検証クエリによって取得されたメモリ内部門エンティティを追跡しないようにすることです。 このエンティティを更新したり、メモリにキャッシュされるメリットのある方法で読み取ったりすることはないため、これを行っても欠点はありません。

DepartmentController.csでは、次に示すように、ValidateOneAdministratorAssignmentPerInstructor メソッドで追跡なしを指定します。

var duplicateDepartment = db.Departments
   .Include("Administrator")
   .Where(d => d.PersonID == department.PersonID)
   .AsNoTracking()
   .FirstOrDefault();

部署の Budget 量の編集を繰り返します。 今回は操作が成功し、サイトが期待どおりに [部門インデックス] ページに戻り、修正された予算値が表示されます。

データベースに送信されたクエリの調査

データベースに送信される実際の SQL クエリを確認できると役立つ場合があります。 これを行うには、デバッガーでクエリ変数を調べるか、クエリの ToString メソッドを呼び出します。 これを試すには、まずシンプルなクエリを見てから、一括読み込み、フィルター処理、並べ替えなどのオプションを追加するとどうなるかを確認します。

Controllers/CourseController で、Index メソッドを次のコードに置き換えます。

public ViewResult Index()
{
    var courses = unitOfWork.CourseRepository.Get();
    return View(courses.ToList());
}

次に、return query.ToList();GenericRepository.csGet メソッドのreturn orderBy(query).ToList(); ステートメントにブレークポイントを設定します。 プロジェクトをデバッグ モードで実行し、[コース インデックス] ページを選択します。 コードがブレークポイントに到達したら、query 変数を調べます。 SQL Server に送信されたクエリが表示されます。 これは単純な Select ステートメントです。

{SELECT 
[Extent1].[CourseID] AS [CourseID], 
[Extent1].[Title] AS [Title], 
[Extent1].[Credits] AS [Credits], 
[Extent1].[DepartmentID] AS [DepartmentID]
FROM [Course] AS [Extent1]}

サンプル Web アプリケーションの [汎用リポジトリ] タブを示すスクリーンショット。クエリ変数が選択されています。

クエリが長すぎて Visual Studio のデバッグ ウィンドウに表示できない場合があります。 クエリ全体を表示するには、変数の値をコピーしてテキスト エディターに貼り付けます。

選択するとドロップダウン メニューが表示された変数値を示すスクリーンショット。[値のコピー] オプションが強調表示されています。

次に、ユーザーが特定の部門をフィルター処理できるように、ドロップダウン リストを [コース インデックス] ページに追加します。 タイトルでコースを並べ替え、Department ナビゲーション プロパティに一括読み込みを指定します。 CourseController.cs で、Index メソッドを次のコードに置き換えます。

public ActionResult Index(int? SelectedDepartment)
{
    var departments = unitOfWork.DepartmentRepository.Get(
        orderBy: q => q.OrderBy(d => d.Name));
    ViewBag.SelectedDepartment = new SelectList(departments, "DepartmentID", "Name", SelectedDepartment);

    int departmentID = SelectedDepartment.GetValueOrDefault(); 
    return View(unitOfWork.CourseRepository.Get(
        filter: d => !SelectedDepartment.HasValue || d.DepartmentID == departmentID,
        orderBy: q => q.OrderBy(d => d.CourseID),
        includeProperties: "Department"));
}

このメソッドは、SelectedDepartment パラメーター内のドロップダウン リストの選択された値を受け取ります。 何も選択しない場合、このパラメーターは null になります。

すべての部門を含む SelectList コレクションが、ドロップダウン リストのビューに渡されます。 SelectList コンストラクターに渡されるパラメーターは、値フィールド名、テキスト フィールド名、および選択した項目を指定します。

Course リポジトリの Get メソッドでは、コードは Department ナビゲーション プロパティのフィルター式、並べ替え順序、および一括読み込みを指定します。 フィルター式は、ドロップダウン リストで何も選択されていない場合 (つまり SelectedDepartment が null の場合)、常に true が返されます。

Views\Course\Index.cshtml で、最初の table タグの直前に次のコードを追加して、ドロップダウン リストと送信ボタンを作成します。

@using (Html.BeginForm())
{
    <p>Select Department: @Html.DropDownList("SelectedDepartment","All")   
    <input type="submit" value="Filter" /></p>
}

GenericRepository クラスにブレークポイントが設定された状態で、[Course Index]\(コース インデックス\) ページを実行します。 ページがブラウザーに表示されるように、コードがブレークポイントにヒットする最初の 2 回を続行します。 ドロップダウン リストから部門を選択し、 Filter をクリックします。

[経済部] が選択された [コース インデックス] ページを示すスクリーンショット。

今回は、最初のブレークポイントがドロップダウン リストの部署クエリ用になります。 次にコードがブレークポイントに到達したら、それをスキップして query 変数を表示し、Course クエリがどのように表示されるかを確認します。 次のように表示されます。

{SELECT 
[Extent1].[CourseID] AS [CourseID], 
[Extent1].[Title] AS [Title], 
[Extent1].[Credits] AS [Credits], 
[Extent1].[DepartmentID] AS [DepartmentID], 
[Extent2].[DepartmentID] AS [DepartmentID1], 
[Extent2].[Name] AS [Name], 
[Extent2].[Budget] AS [Budget], 
[Extent2].[StartDate] AS [StartDate], 
[Extent2].[PersonID] AS [PersonID], 
[Extent2].[Timestamp] AS [Timestamp]
FROM  [Course] AS [Extent1]
INNER JOIN [Department] AS [Extent2] ON [Extent1].[DepartmentID] = [Extent2].[DepartmentID]
WHERE (@p__linq__0 IS NULL) OR ([Extent1].[DepartmentID] = @p__linq__1)}

クエリが Course データと共に Department データを読み込む JOIN クエリになり、WHERE 句が含まれていることを確認できます。

プロキシ クラスの操作

Entity Framework によってエンティティ インスタンスが作成される際 (クエリを実行する場合など)、そのインスタンスは多くの場合、エンティティのプロキシとして機能する、動的に生成された派生型のインスタンスとして作成されます。 このプロキシは、プロパティがアクセスされたときにアクションを自動的に実行するフックを挿入するために、エンティティの一部の仮想プロパティをオーバーライドします。 たとえば、このメカニズムは、リレーションシップの遅延読み込みをサポートするために使用されます。

ほとんどの場合、プロキシのこの使用に注意する必要はありませんが、例外があります。

  • 一部のシナリオでは、場合により、Entity Framework でプロキシ インスタンスが作成されないようにする必要があります。 たとえば、プロキシ インスタンス以外のインスタンスをシリアル化する方が、プロキシ インスタンスをシリアル化するよりも効率的な場合があります。
  • new 演算子を使用してエンティティ クラスをインスタンス化すると、プロキシ インスタンスは取得されません。 つまり、遅延読み込みや自動変更追跡などの機能は取得しません。 これは通常問題ありません。データベースにない新しいエンティティを作成するため、通常は遅延読み込みを必要としません。また、エンティティを明示的に Added としてマークする場合は、通常、変更の追跡は必要ありません。 ただし、遅延読み込みが必要で、変更の追跡が必要な場合は、DbSet クラスのCreate メソッドを使用して、プロキシを使用して新しいエンティティ インスタンスを作成できます。
  • プロキシ型から実際のエンティティ型を取得したい場合があります。 ObjectContext クラスの GetObjectType メソッドを使用して、プロキシ型インスタンスの実際のエンティティ型を取得できます。

詳細については、Entity Framework チームブログの「 プロキシを使用した作業 を参照してください。

変更の自動検出を無効にする

Entity Framework では、エンティティの現在の値と元の値を比較して、エンティティがどのように変更されたか (およびそれによって、どの更新プログラムをデータベースに送信する必要があるか) を判断します。 元の値は、エンティティが照会またはアタッチされたときに格納されます。 変更の自動検出を行うメソッドには、次のようなものがあります。

  • DbSet.Find
  • DbSet.Local
  • DbSet.Remove
  • DbSet.Add
  • DbSet.Attach
  • DbContext.SaveChanges
  • DbContext.GetValidationErrors
  • DbContext.Entry
  • DbChangeTracker.Entries

多数のエンティティを追跡していて、これらのいずれかのメソッドをループ内で何度も呼び出す場合、AutoDetectChangesEnabled プロパティを使用して変更の自動検出を一時的にオフにすると、パフォーマンスが大幅に向上する場合があります。 詳細については、「 変更の自動検出」を参照してください。

変更を保存するときに検証を無効にする

SaveChanges メソッドを呼び出すと、既定では、Entity Framework は、データベースを更新する前に、変更されたすべてのエンティティのすべてのプロパティのデータを検証します。 多数のエンティティを更新し、既にデータを検証している場合、この作業は不要であり、検証を一時的に無効にすることで、変更を保存するプロセスの時間を短縮できます。 これを行うには、ValidateOnSaveEnabled プロパティを 使用します。 詳細については、検証に関するページを参照してください。

まとめ

これで、ASP.NET MVC アプリケーションでの Entity Framework の使用に関する一連のチュートリアルは終了です。 他の Entity Framework リソースへのリンクは、ASP.NET データ アクセス コンテンツ マップに関するページにあります。

Web アプリケーションをビルドした後にデプロイする方法の詳細については、MSDN ライブラリの「展開コンテンツ マップ ASP.NET を参照してください。

認証や承認など、MVC に関連するその他のトピックについては、 MVC の推奨リソースを参照してください。

謝辞

  • Tom Dykstra は、このチュートリアルの元のバージョンを記述し、Microsoft Web Platform and Tools コンテンツ チームのシニア プログラミング ライターです。
  • Rick Anderson (twitter @RickAndMSFT) はこのチュートリアルを共同編集し、EF 5 と MVC 4 用に更新する作業のほとんどを行いました。 Rick は、Azure と MVC に重点を置く Microsoft のシニア プログラミング ライターです。
  • Rowan Miller および Entity Framework チームの他のメンバーは、コード レビューを支援し、EF 5 のチュートリアルの更新中に発生した移行に関する多くの問題のデバッグを支援しました。

VB

チュートリアルが最初に作成されたとき、完成したダウンロード プロジェクトの C# バージョンと VB バージョンの両方を提供しました。 この更新プログラムでは、各章の C# ダウンロード可能なプロジェクトを提供し、シリーズのどこでも簡単に開始できるようにしていますが、時間制限やその他の優先順位のため、VB ではこれを行いませんでした。 これらのチュートリアルを使用して VB プロジェクトをビルドし、他のユーザーと共有する場合は、お知らせください。

エラーと回避策

コピーを作成またはシャドウできない

エラー メッセージ:

そのファイルが既に存在する場合、'DotNetOpenAuth.OpenId' を作成/シャドウ コピーできません。

解決方法:

数秒待ってから、ページを更新します。

Update-Database が認識されない

エラー メッセージ:

"Update-Database" という語が、コマンドレット、関数、スクリプト ファイル、または操作可能なプログラムの名前として認識されません。 名前が正しく記述されていることを確認し、パスが含まれている場合はそのパスが正しいことを確認してから、再試行してください。(PMC の Update-Database コマンドから)。

解決方法:

Visual Studio を終了します。 プロジェクトを再度開き、もう一度やり直してください。

検証に失敗しました

エラー メッセージ:

1 つ以上のエンティティの検証に失敗しました。 詳細については、'EntityValidationErrors' プロパティを参照してください。 (PMC の Update-Database コマンドから)。

解決方法:

この問題の原因の 1 つは、Seed メソッドの実行時の検証エラーです。 Seed メソッドのデバッグに関するヒントについては、「Entity Framework (EF) DB のシード処理とデバッグ」を 参照してください。

HTTP 500.19 エラー

エラー メッセージ:

HTTP エラー 500.19 - 内部サーバー エラー
ページの関連する構成データが無効であるため、要求されたページにアクセスできません。

解決方法:

このエラーの要因の 1 つは、ソリューションの複数のコピーがあり、それぞれが同じポート番号を使用していることです。 通常、この問題を解決するには、Visual Studio のすべてのインスタンスを終了してから、作業中のプロジェクトを再起動します。 それでも問題が解決しない場合は、ポート番号を変更してみてください。 プロジェクト ファイルを右クリックし、[プロパティ] をクリックします。 [Web] タブを選択し、[プロジェクトの URL] テキスト ボックスでポート番号を変更します。

SQL Server インスタンスの位置を特定しているときのエラー

エラー メッセージ:

SQL Server への接続を確立しているときに、ネットワーク関連またはインスタンス固有のエラーが発生しました。 サーバーが見つからないかアクセスできません。 インスタンス名が正しいこと、および SQL Server がリモート接続を許可するように構成されていることを確認してください。 (プロバイダー:SQL ネットワーク インターフェイス、エラー:26 - 指定されたサーバーまたはインスタンスの位置を特定しているときにエラーが発生しました)

解決方法:

接続文字列を確認します。 データベースを手動で削除した場合は、構築文字列内のデータベース名を変更します。