ASP.NET MVCアプリでのリポジトリパターンの実装
リポジトリ・パターンは、エンタープライズ・レベルのアプリケーションを作成するための最も一般的なパターンの 1 つです。これにより、アプリケーション内のデータを直接操作することが制限され、データベース操作、ビジネスロジック、およびアプリケーションのUI用の新しいレイヤーが作成されます。
リポジトリパターンは、エンタープライズレベルのアプリケーションを作成するための最も一般的なパターンの1つです。これにより、アプリケーション内のデータを直接操作することが制限され、データベース操作、ビジネス ロジック、およびアプリケーションの UI に新しいレイヤーが作成されます。アプリケーションがリポジトリパターンに従わない場合、次の問題が発生する可能性があります。
- 重複するデータベース操作コード
- データベース操作とビジネスロジックを単体テストするためのUIの必要性
- 単体テストビジネスロジックへの外部依存関係の必要性
- データベースキャッシュの実装が難しいなど
リポジトリ・パターンを使用すると、次のような多くの利点があります。
- ビジネスロジックは、データアクセスロジックなしで単体テストできます。
- データベース・アクセス・コードは再利用できます。
- データベースアクセスコードは一元管理されるため、キャッシュなどのデータベースアクセスポリシーを簡単に実装できます。
- ドメインロジックの実装は簡単です。
- ドメイン エンティティまたはビジネス エンティティは、注釈を使用して厳密に型指定されています。などなど。
インターネット上には、リポジトリパターンに関する何百万もの記事が書かれていますが、この記事では、ASP.NET MVCアプリケーションに実装する方法に焦点を当てます。それでは始めましょう!
先に進んでASP.NET MVCのリポジトリ パターンについて学ぶ前に、Web アプリケーションをより迅速に作成して実行するのに役立つ Infragistics jQuery ベースのライブラリIgnite UIを確認することをお勧めします。Ignite UI for JavaScript ライブラリを使用すると、HTML5、jQuery、Angular、React、またはASP.NET MVCの複雑な LOB 要件をすばやく解決できます。(Ignite UIの無料トライアルはこちらからダウンロードできます)。
プロジェクト構造
アプリケーションのプロジェクト構造の作成から始めましょう。次の 4 つのプロジェクトを作成します。
- コアプロジェクト
- インフラプロジェクト
- テストプロジェクト
- MVC Project
各プロジェクトには独自の目的があります。プロジェクトの名前から、コア プロジェクトとインフラストラクチャ プロジェクトはクラス ライブラリ、Web プロジェクトは MVC プロジェクト、テスト プロジェクトは単体テスト プロジェクトです。最終的に、ソリューション エクスプローラーのプロジェクトは、次の図のようになります。

この投稿を進めるにつれて、各プロジェクトの目的について詳しく学びますが、まず、各プロジェクトの主な目的を次のように要約できます。
これまでのところ、さまざまなプロジェクトに対する私たちの理解は明らかです。それでは、各プロジェクトを 1 つずつ実装してみましょう。実装中に、各プロジェクトの責任を詳細に検討します。
コアプロジェクト
コアプロジェクトでは、エンティティとリポジトリインターフェイス、またはデータベース操作インターフェイスを保持します。コア・プロジェクトには、ドメイン・エンティティーと、ドメイン・エンティティーに必要なデータベース操作に関する情報が含まれています。理想的なシナリオでは、コアプロジェクトは外部ライブラリに依存しないようにする必要があります。ビジネスロジック、データベース操作コードなどが含まれていてはなりません。
つまり、コアプロジェクトには次のものが含まれている必要があります。
- ドメインエンティティ
- ドメイン・エンティティー上のリポジトリー・インターフェースまたはデータベース操作インターフェース
- ドメイン固有のデータ注釈
コアプロジェクトには以下を含めることはできません。
- データベース操作用の外部ライブラリ
- Business logic
- データベース操作コード
ドメインエンティティを作成する際には、ドメインエンティティのプロパティに対する制限についても決定する必要があります。
- 特定のプロパティが必要かどうか。たとえば、Product エンティティの場合、製品の名前は必須プロパティである必要があります。
- 特定のプロパティの値が指定された範囲内にあるかどうか。たとえば、Product エンティティの場合、価格プロパティは指定された範囲内になければなりません。
- 特定のプロパティの最大長に値を指定しないかどうか。たとえば、Product エンティティの場合、name プロパティの値は最大長より小さくする必要があります。
ドメインエンティティのプロパティには、このようなデータ注釈が多数存在する可能性があります。これらのデータアノテーションについて考えるには、次の 2 つの方法があります。
- ドメインエンティティの一部として
- データベース操作ロジックの一部として
データアノテーションをどのように見るかは、純粋に私たち次第です。それらをデータベース操作の一部と見なす場合は、データベース操作ライブラリAPIを使用して制限を適用できます。インフラストラクチャ プロジェクトのデータベース操作に Entity Framework を使用するため、Entity Framework Fluent API を使用してデータに注釈を付けることができます。
それらをドメインの一部と見なす場合は、System.ComponentModel.DataAnnotationsライブラリを使用してデータに注釈を付けることができます。これを使用するには、コアプロジェクトのReferenceフォルダを右クリックし、Add Referenceをクリックします。[フレームワーク] タブから[System.ComponentModel.DataAnnotations] を選択し、プロジェクトに追加します。
ProductApp を作成しているので、Product エンティティの作成から始めましょう。エンティティクラスを追加するには、コアプロジェクトを右クリックしてクラスを追加し、クラスにProductという名前を付けます。
using System.ComponentModel.DataAnnotations;
namespace ProductApp.Core
{
public class Product
{
public int Id { get; set; }
[Required]
[MaxLength(100)]
public string Name { get; set; }
[Required]
public double Price { get; set; }
public bool inStock { get; set; }
}
}
Product エンティティのプロパティにRequired と MaxLengthの注釈を付けました。これらの注釈は両方ともSystem.ComponentModel.DataAnnotations の一部です。ここでは、制限をドメインの一部として考慮したため、コアプロジェクト自体でデータアノテーションを使用しました。
Product Entityクラスを作成し、それにデータアノテーションも適用しました。それでは、リポジトリインターフェイスを作成しましょう。しかし、それを作成する前に、リポジトリインターフェイスとは何かを理解しましょう。
リポジトリ・インターフェースは、ドメイン・エンティティで可能なすべてのデータベース操作を定義します。ドメインエンティティに対して実行できるすべてのデータベース操作はドメイン情報の一部であるため、リポジトリインターフェイスをコアプロジェクトに配置します。これらの操作をどのように実行できるかは、インフラストラクチャ プロジェクトの一部になります。
リポジトリインターフェイスを作成するには、コアプロジェクトを右クリックし、Interfacesという名前のフォルダーを追加します。[インターフェイス] フォルダーを作成したら、[インターフェイス] フォルダーを右クリックして [新しい項目の追加] を選択し、[コード] タブから [インターフェイス] を選択します。インターフェイスにIProductRepositoryという名前を付けます
using System.Collections.Generic;
namespace ProductApp.Core.Interfaces
{
public interface IProductRepository
{
void Add(Product p);
void Edit(Product p);
void Remove(int Id);
IEnumerable GetProducts(); Product FindById(int Id);
}
}
これで、Product エンティティ クラスと Product Repository インターフェイスが作成されました。この時点で、コアプロジェクトは次のようになります。

先に進み、コアプロジェクトを構築して、すべてが整っていることを確認し、インフラストラクチャプロジェクトの作成に進みましょう。
インフラプロジェクト
インフラストラクチャ プロジェクトの主な目的は、データベース操作を実行することです。データベース操作に加えて、Webサービスの使用、IO操作などの実行も可能です。したがって、主に、インフラストラクチャプロジェクトは次の操作を実行する場合があります。
- Database operations
- WCF と Web サービスの操作
- IO operations
データベース操作を実行するために、任意のデータベーステクノロジーを使用できます。この投稿では、Entity Framework を使用します。そこで、Code First アプローチを使用してデータベースを作成します。Code First アプローチでは、データベースはクラスに基づいて作成されます。ここでは、コアプロジェクトのドメインエンティティに基づいてデータベースが作成されます。
コア プロジェクト ドメイン エンティティからデータベースを作成するには、次のタスクを実行する必要があります。
- Create DataContext class
- 接続文字列を構成する
- データベースにデータをシードする DataBase Initializer クラスを作成する
- IProductRepsitory インターフェイスの実装
参照の追加
まず、Entity Framework プロジェクトと ProductApp.Core プロジェクトへの参照を追加しましょう。Entity Framework を追加するには、インフラストラクチャ プロジェクトを右クリックし、[Nuget パッケージの管理] をクリックします。[パッケージ マネージャー] ウィンドウで Entity Framework を検索し、最新の安定バージョンをインストールします。
ProductApp.Core プロジェクトの参照を追加するには、Infrastructure プロジェクトを右クリックし、[参照の追加] をクリックします。[参照ウィンドウ] で [プロジェクト] タブをクリックし、[ProductApp.Core] を選択します。
DataContext class
DataContext クラスの目的は、Entity Framework Code First アプローチでデータベースを作成することです。DataContextクラスのコンストラクターに接続文字列を渡します。接続文字列を読み取ることで、Entity Framework によってデータベースが作成されます。接続文字列が指定されていない場合、Entity Framework はローカル データベース サーバーにデータベースを作成します。
In the DataContext class:
- DbSet 型プロパティを作成します。これは、Product エンティティのテーブルの作成を担当します
- DataContextクラスのコンストラクタで、接続文字列を渡して、サーバー名、データベース名、ログイン情報など、データベースを作成するための情報を指定します。接続文字列の名前を渡す必要があります。データベースが作成される名前
- 接続文字列が渡されない場合、Entity Framework はローカル データベース サーバー内のデータ コンテキスト クラスの名前を使用して作成します。
- productdatacontext クラスは DbContext クラスを継承します
ProductDataContext クラスは、次のリストに示すように作成できます。
using ProductApp.Core;
using System.Data.Entity;
namespace ProductApp.Infrastructure
{
public class ProductContext : DbContext
{
public ProductContext() : base("name=ProductAppConnectionString") {}
public DbSet Products { get; set; }
}
}
次に、接続文字列に取り組む必要があります。前述のように、接続文字列を渡してデータベース作成情報を指定するか、Entity Framework に応答して既定の場所に既定のデータベースを作成できます。ProductDataContextクラスのコンストラクターでProductAppConnectionStringという接続文字列名を渡したため、接続文字列を指定します。App.Config ファイルでは、次の一覧に示すように、ProductAppConnectionString 接続文字列を作成できます。
<add name="ProductAppConnectionString" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=ProductAppJan;Integrated Security=True;MultipleActiveResultSets=true" providerName="System.Data.SqlClient"/>
データベース初期化子クラス
データベース初期化子クラスを作成して、作成時にデータベースに初期値をシードします。データベース初期化子クラスを作成するには、DropCreateDatabaseIfModelChnagesから継承するクラスを作成します。データベース初期化子クラスを作成するために継承できるクラスの他のオプションがあります。DropCreateDatabaseIfModelChnagesクラスを継承すると、モデルが変更されるたびに新しいデータベースが作成されます。したがって、たとえば、Product エンティティ クラスにプロパティを追加または削除すると、Entity Framework は既存のデータベースを削除し、新しいデータベースを作成します。もちろん、データも失われるため、これは優れたオプションではないため、データベース初期化子クラスを継承する他のオプションを検討することをお勧めします。
データベース初期化子クラスは、次のリストに示すように作成できます。ここでは、製品テーブルを 2 行でシードします。データをシードするには:
- Override Seed method
- Context.Products に製品を追加する
- Context.SaveChanges() を呼び出す
using ProductApp.Core;
using System.Data.Entity;
namespace ProductApp.Infrastructure {
public class ProductInitalizeDB : DropCreateDatabaseIfModelChanges {
protected override void Seed(ProductContext context) {
context.Products.Add(
new Product { Id = 1, Name = "Rice", inStock = true, Price = 30 });
context.Products.Add(
new Product { Id = 2, Name = "Sugar", inStock = false, Price = 40 });
context.SaveChanges();
base.Seed(context);
}
}
}
これまでのところ、データベースを作成するために Entity Framework Code First 関連のすべての作業を実行しました。次に、Core プロジェクトの IProductRepository インターフェイスを具象 ProductRepository クラスに実装しましょう。
Repository Class
これは、製品エンティティに対してデータベース操作を実行するクラスです。このクラスでは、Core プロジェクトから IProductRepository インターフェイスを実装します。まず、ProductRepository クラスをインフラストラクチャ プロジェクトに追加し、IProductRepository インターフェイスを実装しましょう。データベース操作を実行するために、単純な LINQ to Entity クエリを記述します。製品リポジトリクラスは、次のリストに示すように作成できます。
using ProductApp.Core.Interfaces;
using System.Collections.Generic;
using System.Linq;
using ProductApp.Core;
namespace ProductApp.Infrastructure {
public class ProductRepository : IProductRepository {
ProductContext context = new ProductContext();
public void Add(Product p) {
context.Products.Add(p);
context.SaveChanges();
}
public void Edit(Product p) {
context.Entry(p).State = System.Data.Entity.EntityState.Modified;
}
public Product FindById(int Id) {
var result = (from r in context.Products where r.Id == Id select r).FirstOrDefault();
return result;
}
public IEnumerable GetProducts() {
return context.Products;
}
public void Remove(int Id) {
Product p = context.Products.Find(Id);
context.Products.Remove(p);
context.SaveChanges();
}
}
}
ここまで、Data Context クラス、Database Initializer クラス、および Repository クラスを作成しました。インフラストラクチャ プロジェクトを構築して、すべてが整っていることを確認しましょう。ProductApp.Infrastructure プロジェクトは、次の図のようになります。

これで、インフラストラクチャ プロジェクトの作成は完了です。データベース操作関連のすべてのクラスをインフラストラクチャー・プロジェクト内に記述し、データベース関連のロジックはすべて一元的にまとめられています。データベースロジックの変更が必要な場合は、インフラストラクチャプロジェクトのみを変更する必要があります。
テストプロジェクト
リポジトリパターンの最大の利点は、テストの容易さです。これにより、プロジェクトの他のコンポーネントに依存することなく、さまざまなコンポーネントを単体テストできます。たとえば、機能の正確性を検証するためにデータベース操作を実行するRepositoryクラスを作成したので、単体テストを行う必要があります。また、WebプロジェクトやUIに依存せずにRepositoryクラスのテストを作成できるはずです。リポジトリパターンに従っているため、MVCプロジェクト(UI)に依存せずにインフラストラクチャプロジェクトの単体テストを作成できます。
ProductRepository クラスの単体テストを記述するには、Test プロジェクトに次の参照を追加しましょう。
- ProductApp.Coreプロジェクトのリファレンス
- ProductApp.Infrastructureプロジェクトのリファレンス
- Entity Framework package
Entity Framework を追加するには、Test プロジェクトを右クリックし、 [Nuget パッケージの管理] をクリックします。パッケージ マネージャー ウィンドウで、Entity Framework を検索し、最新の安定バージョンをインストールします。
ProductApp.Core プロジェクトの参照を追加するには、Test プロジェクトを右クリックし、[参照の追加] をクリックします。[参照ウィンドウ] で [プロジェクト] タブをクリックし、[ProductApp.Core] を選択します。
ProductApp.Infrastructure プロジェクトの参照を追加するには、Test プロジェクトを右クリックし、[参照の追加] をクリックします。[参照ウィンドウ] で [プロジェクト] タブをクリックし、[ProductApp.Infrastructure] を選択します。
接続文字列をコピーする
Visual Studio は、実行中のプロジェクトの構成ファイルを常に読み取ります。インフラストラクチャ プロジェクトをテストするために、テスト プロジェクトを実行します。したがって、接続文字列は Test プロジェクトの App.Config の一部である必要があります。インフラストラクチャ プロジェクトから接続文字列をコピーして、テスト プロジェクトに貼り付けてみましょう。
必要な参照をすべて追加し、接続文字列をコピーしました。次に、テストクラスを設定しましょう。ProductRepositoryTest という名前のテスト クラスを作成します。テスト初期化は、テストが実行される前に実行される関数です。テストを実行する前に、ProductRepository クラスのインスタンスを作成し、ProductDbInitalize クラスを呼び出してデータをシードする必要があります。テスト初期化子は、次のリストに示すように記述できます。
[TestClass]
public class ProductRepositoryTest {
ProductRepository Repo;
[TestInitialize]
public void TestSetup() {
ProductInitalizeDB db = new ProductInitalizeDB();
System.Data.Entity.Database.SetInitializer(db);
Repo = new ProductRepository();
}
}
これで、テスト初期化子を作成しました。次に、ProductInitalizeDBクラスがProductテーブルの2行をシードするかどうかを検証するための最初のテストを作成しましょう。これは最初に実行するテストであるため、データベースが作成されるかどうかも検証します。したがって、基本的にはテストを書いています。
- データベースの作成を確認するには
- Product Database Initializer の seed メソッドによって挿入された行数を確認するには
[TestMethod]
public void IsRepositoryInitalizeWithValidNumberOfData() {
var result = Repo.GetProducts();
Assert.IsNotNull(result);
var numberOfRecords = result.ToList().Count;
Assert.AreEqual(2, numberOfRecords);
}
ご覧のとおり、Repository GetProducts() 関数を呼び出して、データベースの作成中に挿入されたすべての Products をフェッチしています。このテストでは、GetProducts() が期待どおりに動作するかどうかを実際に検証し、データベースの作成も検証します。[テスト エクスプローラー] ウィンドウで、検証のためにテストを実行できます。

テストを実行するには、まずテスト プロジェクトをビルドし、トップ メニューから [Test->Windows-Test Explorer] を選択します。テスト エクスプローラーには、リストされているすべてのテストが表示されます。テストを選択し、[実行] をクリックします。
先に進み、リポジトリでの Add Product 操作を検証するためのテストをもう 1 つ作成しましょう。
[TestMethod]
public void IsRepositoryAddsProduct() {
Product productToInsert =
new Product { Id = 3, inStock = true, Name = "Salt", Price = 17
};
Repo.Add(productToInsert);
// If Product inserts successfully,
// number of records will increase to 3
var result = Repo.GetProducts();
var numberOfRecords = result.ToList().Count;
Assert.AreEqual(3, numberOfRecords);
}
製品の挿入を確認するために、リポジトリで Add 関数を呼び出します。Product が正常に追加されると、レコード数が 2 から 3 に増加し、それを検証しています。テストを実行すると、テストに合格したことがわかります。

このようにして、Product Repositoryクラスからすべてのデータベース操作のテストを記述できます。これで、テストが合格しているため、Repositoryクラスが正しく実装されたことが確認でき、InfrastructureおよびCoreプロジェクトは任意のUI(この場合はMVC)プロジェクトで使用できます。
MVC または Web プロジェクト
最後に、MVCプロジェクトにたどり着きました!テストプロジェクトと同様に、次の参照を追加する必要があります
- ProductApp.Coreプロジェクトのリファレンス
- ProductApp.Infrastructureプロジェクトのリファレンス
ProductApp.Core プロジェクトの参照を追加するには、MVC プロジェクトを右クリックし、[参照の追加] をクリックします。[参照ウィンドウ] で [プロジェクト] タブをクリックし、[ProductApp.Core] を選択します。
ProductApp.Infrastructure プロジェクトの参照を追加するには、MVC プロジェクトを右クリックし、[参照の追加] をクリックします。[参照ウィンドウ] で [プロジェクト] タブをクリックし、[ProductApp.Infrastructure] を選択します。
接続文字列をコピーする
Visual Studio は、実行中のプロジェクトの構成ファイルを常に読み取ります。インフラストラクチャ プロジェクトをテストするには、テスト プロジェクトを実行するため、接続文字列はテスト プロジェクトの App.Config の一部である必要があります。簡単にするために、インフラストラクチャ プロジェクトから接続文字列をコピーしてテスト プロジェクトに貼り付けましょう。
アプリケーションの足場
MVC コントローラーの足場を用意するためのすべての準備が整っている必要があります。スキャフォールディングするには、次の図に示すように、Controller フォルダーを右クリックし、Entity Framework を使用して [MVC 5 Controller with Views] を選択します。

次に、[コントローラーの追加] ウィンドウが表示されます。ここでは、モデルクラスとデータコンテキストクラス情報を提供する必要があります。このプロジェクトでは、モデル クラスは Core プロジェクトの Product クラスであり、Data コンテキスト クラスは Infrastructure プロジェクトの ProductDataContext クラスです。下の画像に示すように、ドロップダウンから両方のクラスを選択しましょう。

また、[ビューの生成]、[参照スクリプト ライブラリ]、および [レイアウト ページの使用] オプションが選択されていることを確認する必要があります。
[追加] をクリックすると、Visual Studio は Views/Products フォルダー内に ProductsController と Views を作成します。MVC プロジェクトは、次の図に示す構造を持つ必要があります。

この時点で、先に進んでアプリケーションを実行すると、Product エンティティに対して CRUD 操作を実行できるようになります。

足場の問題
しかし、まだ終わっていません!ProductsController クラスを開いて、コードを調べてみましょう。一番最初の行で、問題を見つけます。MVC スキャフォールディングを使用したため、MVC はデータベース操作を実行するために ProductContext クラスのオブジェクトを作成しています。

コンテキスト クラスへの依存関係は、UI プロジェクトとデータベースを相互に緊密に結び付けます。ご存知のように、DatacontextクラスはEntity Frameworkコンポーネントです。MVC プロジェクトには、インフラストラクチャ プロジェクトで使用されているデータベース テクノロジを知らせたくありません。一方、Datacontext クラスはテストしていません。ProductRepositoryクラスをテストしました。理想的には、ProductContext クラスの代わりに ProductRepository クラスを使用して、MVC コントローラーでデータベース操作を実行する必要があります。 まとめると、
- MVC スキャフォールディングは、データ コンテキスト クラスを使用してデータベース操作を実行します。データ コンテキスト クラスは Entity Framework コンポーネントであるため、その使用は UI (MVC) とデータベース (EF) テクノロジを密接に結合します。
- データコンテキストクラスは単体テストされていないため、それを使用することはお勧めできません。
- テスト済みのProductRepositoryクラスがあります。これをコントローラー内で使用して、データベース操作を実行する必要があります。また、ProductRepository クラスはデータベース テクノロジを UI に公開しません。
データベース操作に ProductRepository クラスを使用するには、ProductsController クラスをリファクタリングする必要があります。そのためには、次の 2 つの手順に従う必要があります。
- ProductContext クラスの代わりに ProductRepository クラスのオブジェクトを作成します。
- ProductContext クラスのメソッドの代わりに、ProductRepository クラスのメソッドを呼び出して、Product エンティティに対してデータベース操作を実行します。
以下のリストでは、ProductContext を使用してコードをコメントし、ProductRepository メソッドを呼び出しました。リファクタリング後、ProductController クラスは次のようになります。
using System;
using System.Net;
using System.Web.Mvc;
using ProductApp.Core;
using ProductApp.Infrastructure;
namespace ProductApp.Web.Controllers {
public class ProductsController : Controller {
// private ProductContext db = new ProductContext();
private ProductRepository db = new ProductRepository();
public ActionResult Index() {
// return View(db.Products.ToList());
return View(db.GetProducts());
}
public ActionResult Details(int? id) {
if (id == null) {
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
// Product product = db.Products.Find(id);
Product product = db.FindById(Convert.ToInt32(id));
if (product == null) {
return HttpNotFound();
}
return View(product);
}
public ActionResult Create() {
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(
[Bind(Include = "Id,Name,Price,inStock")] Product product) {
if (ModelState.IsValid) {
// db.Products.Add(product);
// db.SaveChanges();
db.Add(product);
return RedirectToAction("Index");
}
return View(product);
}
public ActionResult Edit(int? id) {
if (id == null) {
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Product product = db.FindById(Convert.ToInt32(id));
if (product == null) {
return HttpNotFound();
}
return View(product);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(
[Bind(Include = "Id,Name,Price,inStock")] Product product) {
if (ModelState.IsValid) {
// db.Entry(product).State = EntityState.Modified;
// db.SaveChanges();
db.Edit(product);
return RedirectToAction("Index");
}
return View(product);
}
public ActionResult Delete(int? id) {
if (id == null) {
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Product product = db.FindById(Convert.ToInt32(id));
if (product == null) {
return HttpNotFound();
}
return View(product);
}
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id) {
// Product product = db.FindById(Convert.ToInt32(id));
// db.Products.Remove(product);
// db.SaveChanges();
db.Remove(id);
return RedirectToAction("Index");
}
protected override void Dispose(bool disposing) {
if (disposing) {
// db.Dispose();
}
base.Dispose(disposing);
}
}
}
リファクタリング後、アプリケーションをビルドして実行しましょう – そうして CRUD 操作を実行できるはずです。
依存関係の挿入
これで、アプリケーションが稼働しており、リポジトリ パターンを使用して作成されたことに満足しています。しかし、まだ問題があります:ProductsControllerクラス内にProductRepositoryクラスのオブジェクトを直接作成しており、これは望ましくありません。依存関係を反転し、依存関係を挿入するタスクをサードパーティ (一般に DI コンテナとして知られている) に委任したいと考えています。基本的に、ProductsController は DI コンテナーに IProductRepository のインスタンスを返すように要求します。
MVC アプリケーションで使用できる DI コンテナーは多数あります。この例では、最も単純な Unity DI コンテナを使用します。これを行うには、MVC プロジェクトを右クリックし、[Nuget パッケージの管理] をクリックします。NuGet パッケージ マネージャーで Unity.Mvc を検索し、パッケージをインストールします。

Unity.Mvcパッケージがインストールされたら、先に進んでApp_Startフォルダーを開きましょう。App_Start フォルダー内に、UnityConfig.cs ファイルがあります。UnityConfigクラスでは、型を登録する必要があります。これを行うには、UnityConfig クラスで RegisterTypes 関数を開き、以下のリストに示すように型を登録します。
public static void RegisterTypes(IUnityContainer container) {
// TODO: Register your types here
container.RegisterType<iproductrepository, productrepository = "">();
}
Unity DIコンテナに型を登録しました。次に、ProductsController クラスで少しリファクタリングを行いましょう。 ProductsController のコンストラクターでは、リポジトリ インターフェイスへの参照を渡します。アプリケーションが必要とするたびに、Unity DI コンテナーは型を解決することで、ProductRepository の具象オブジェクトをアプリケーションに挿入します。以下のリストに示すように、ProductsControllerをリファクタリングする必要があります。
public class ProductsController : Controller {
IProductRepository db;
public ProductsController(IProductRepository db) {
this.db = db;
}
先に進み、アプリケーションをビルドして実行しましょう。アプリケーションを起動して実行し、リポジトリ パターンと依存関係の挿入を使用して CRUD 操作を実行できる必要があります。
結論
この記事では、リポジトリパターンに従ってMVCアプリケーションを作成する方法を段階的に学習しました。そうすることで、すべてのデータベースロジックを1か所に配置でき、必要なときはいつでもリポジトリを変更してテストするだけで済みます。また、リポジトリ パターンは、アプリケーション UI をデータベース ロジックおよびドメイン エンティティと疎結合し、アプリケーションのテストしやすくします。
また、 HTML5、Angular、React、またはASP.NET MVCで使用できるIgnite UIをチェックすることも忘れないでください。読んでくれてありがとう!
