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 を入力します。

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

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 、コントローラーで必要な任意の種類のフィルター処理や並べ替えを指定できます。 このセクションでは、このようなメソッドを実装する方法について説明します。

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

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 つのコースの [詳細] を選択します)。

[Contoso University Details]\(Contoso 大学の詳細\) ページを示すスクリーンショット。

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

以前に、登録日ごとの学生数を示す 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 で、 メソッドの LINQ ステートメントをAbout次のコードに置き換えます。

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

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

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

更新クエリの呼び出し

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

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

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

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();
}

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

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

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

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

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

Views\Course\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 チームブログの 生 SQL クエリ に関するページを参照してください。

追跡なしのクエリ

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

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

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

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

DepartmentController.cs で、 メソッドと Create メソッドからEdit呼び出すことができる新しいメソッドを追加して、同じ管理者が 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);
        }
    }
}

検証エラーがない場合は、 try メソッドの ブロックに HttpPostEdit コードを追加して、この新しいメソッドを呼び出します。 ブロックは 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]\(部署の編集\) ページを示すスクリーンショット。

例外エラー メッセージは "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();

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

データベースに送信されたクエリの確認

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

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

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

次に、 メソッドの ステートメントと return orderBy(query).ToList(); ステートメントの GenericRepository.csreturn query.ToList();ブレークポイントをGet設定します。 プロジェクトをデバッグ モードで実行し、[コース インデックス] ページを選択します。 コードがブレークポイントに到達したら、変数を 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 渡されるパラメーターは、値フィールド名、テキスト フィールド名、および選択した項目を指定します。

リポジトリの GetCourse メソッドの場合、コードはナビゲーション プロパティのフィルター式、並べ替え順序、および一括読み込みを 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 、[コース インデックス] ページを実行します。 コードがブレークポイントにヒットした最初の 2 回を続行して、ページがブラウザーに表示されるようにします。 ドロップダウン リストから部門を選択し、[ フィルター] をクリックします。

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

今回、最初のブレークポイントは、ドロップダウン リストの部署クエリに対して行われます。 次にコードが 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にデータをJOIN読み込むDepartmentクエリになり、句が含まれていることをWHERE確認できます。

プロキシ クラスの操作

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

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

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

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

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

謝辞

  • Tom Dykstra は、このチュートリアルの元のバージョンを書き、Microsoft Web プラットフォームとツール コンテンツ チームのシニア プログラミング ライターです。
  • 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 検証エラーです。 メソッド のデバッグに関するヒントについては、「Entity Framework (EF) DB のシード 処理 Seed とデバッグ」を参照してください。

HTTP 500.19 エラー

エラー メッセージ:

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

解決方法:

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

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

エラー メッセージ:

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

解決方法 :

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