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 を使用して一括更新を行うには、データベース内のすべてのコースのクレジット数を更新する新しいページを作成します。
また、追跡なしのクエリを使用するには、[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 を選択します)。
他の種類のオブジェクトを返すクエリの呼び出し
以前に、登録日ごとの学生数を示す 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 の管理者が、すべてのコースの単位数を変更するなどの、データベースでの一括変更をする機能を求めているとします。 大学に多くのコースがある場合は、それらすべてをエンティティとして取得し、それらを個別に変更するのは非効率的です。 このセクションでは、ユーザーがすべてのコースのクレジット数を変更する要因を指定できる Web ページを実装し、SQL UPDATE
ステートメントを実行して変更を行います。 Web ページは次の図のようになります。
前のチュートリアルでは、汎用リポジトリを使用して、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();
}
このメソッドは、 HttpGet
と HttpPost
の両方に使用されます。 HttpGet
UpdateCourseCredits
メソッドを実行すると、前の図に示すように、multiplier
変数は null になり、ビューには空のテキスト ボックスと送信ボタンが表示されます。
Update ボタンがクリックされ、HttpPost
メソッドが実行されると、multiplier
テキスト ボックスに値が入力されます。 その後、このコードは、影響を受ける行の数を返すリポジトリ UpdateCourseCredits
メソッドを呼び出し、その値は ViewBag
オブジェクトに格納されます。 ビューは、 ViewBag
オブジェクト内の影響を受ける行の数を受け取ると、次の図に示すように、テキスト ボックスと送信ボタンの代わりにその数を表示します。
[コース クレジットの更新] ページの 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
メソッドを実行します。 テキスト ボックスに数値を入力します。
[更新] をクリックします。 影響を受けた行の数が表示されます。
[リストに戻る] をクリックして、単位数が変更されたコースの一覧を表示します。
生の 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 ページをもう一度実行し、今度は Budget の量を変更します。 保存をクリックすると、エラー ページが表示されます。
例外エラー メッセージは "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.csとGet
メソッドの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]}
クエリが長すぎて 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 - 指定されたサーバーまたはインスタンスの位置を特定しているときにエラーが発生しました)
解決方法:
接続文字列を確認します。 データベースを手動で削除した場合は、構築文字列内のデータベース名を変更します。