web-dev-qa-db-ja.com

ASP.NET MVCでのデータアクセスの分離

MVCでの最初の実際のクラックで、業界標準とベストプラクティスに従っていることを確認したいと思います。この場合は、C#を使用したASP.NET MVCです。

モデルにはEntity Framework 4.1を使用し、コードファーストオブジェクト(データベースは既に存在します)を使用するため、データベースからデータを取得するためのDBContextオブジェクトがあります。

私がasp.netのWebサイトで行ったデモでは、コントローラーにデータアクセスコードが含まれています。これは、特にDRY(繰り返さないでください))プラクティスに従う場合、私には正しくないと思われます。

たとえば、私が公共図書館で使用するWebアプリケーションを作成していて、カタログで書籍を作成、更新、削除するためのコントローラーがあるとします。

アクションのいくつかはISBNを取り、「Book」オブジェクトを返す必要がある場合があります(これはおそらく100%有効なコードではないことに注意してください):

public class BookController : Controller
{
    LibraryDBContext _db = new LibraryDBContext();

    public ActionResult Details(String ISBNtoGet)
    {
        Book currentBook = _db.Books.Single(b => b.ISBN == ISBNtoGet);
        return View(currentBook);
    }

    public ActionResult Edit(String ISBNtoGet)
    {
        Book currentBook = _db.Books.Single(b => b.ISBN == ISBNtoGet);
        return View(currentBook);
    }
}

代わりに、should実際にdbコンテキストオブジェクトに1つのBookを返すメソッドがありますか? WebアプリケーションのどこかでISBNによってBookオブジェクトを取得する必要があるかもしれないので、それは私にとってはより良い分離のようであり、DRYを促進するのに役立ちます。

public partial class LibraryDBContext: DBContext
{
    public Book GetBookByISBN(String ISBNtoGet)
    {
        return Books.Single(b => b.ISBN == ISBNtoGet);
    }
}

public class BookController : Controller
{
    LibraryDBContext _db = new LibraryDBContext();

    public ActionResult Details(String ISBNtoGet)
    {
        return View(_db.GetBookByISBN(ISBNtoGet));
    }

    public ActionResult Edit(ByVal ISBNtoGet as String)
    {
        return View(_db.GetBookByISBN(ISBNtoGet));
    }
}

これは私のアプリケーションのコーディングで従うべき有効なルールのセットですか?

または、もっと主観的な質問は、「これを行う正しい方法ですか?」

35
scott.korin

一般的には、コントローラーにいくつかのことのみを実行させたい場合:

  1. 着信リクエストを処理する
  2. 処理を一部のビジネスオブジェクトに委任する
  3. ビジネス処理の結果をレンダリングに適したビューに渡します

コントローラーにanyデータアクセスや複雑なビジネスロジックがあってはなりません。

[最も単純なアプリでは、おそらくコントローラーの基本的なデータCRUDアクションで済むでしょうが、単純なGet呼び出しとUpdate呼び出し以上のものを追加し始めると、処理を別のクラスに分割したくなるでしょう。 ]

通常、コントローラーは実際の処理作業を行うために「サービス」に依存します。サービスクラスでは、データソース(この場合はDbContext)をmayで直接操作できますが、繰り返しますが、データアクセスに加えてビジネスルールを使用する場合は、ビジネスロジックをデータアクセスから分離する必要があります。

その時点で、おそらくデータアクセスだけを行うクラスができます。これはリポジトリと呼ばれることもありますが、名前が何であるかは問題ではありません。ポイントは、データベースにデータを出し入れするためのすべてのコードが1か所にあるということです。

私が取り組んだすべてのMVCプロジェクトについて、常に次のような構造になっています。

コントローラ

public class BookController : Controller
{
    ILibraryService _libraryService;

    public BookController(ILibraryService libraryService)
    {
        _libraryService = libraryService;
    }

    public ActionResult Details(String isbn)
    {
        Book currentBook = _libraryService.RetrieveBookByISBN(isbn);
        return View(ConvertToBookViewModel(currentBook));
    }

    public ActionResult DoSomethingComplexWithBook(ComplexBookActionRequest request)
    {
        var responseViewModel = _libraryService.ProcessTheComplexStuff(request);
        return View(responseViewModel);
    }
}

ビジネスサービス

public class LibraryService : ILibraryService
{
     IBookRepository _bookRepository;
     ICustomerRepository _customerRepository;

     public LibraryService(IBookRepository bookRepository, 
                           ICustomerRepository _customerRepository )
     {
          _bookRepository = bookRepository;
          _customerRepository = customerRepository;
     }

     public Book RetrieveBookByISBN(string isbn)
     {
          return _bookRepository.GetBookByISBN(isbn);
     }

     public ComplexBookActionResult ProcessTheComplexStuff(ComplexBookActionRequest request)
     {
          // Possibly some business logic here

          Book book = _bookRepository.GetBookByISBN(request.Isbn);
          Customer customer = _customerRepository.GetCustomerById(request.CustomerId);

          // Probably more business logic here

          _libraryRepository.Save(book);

          return complexBusinessActionResult;

     } 
}

リポジトリ

public class BookRepository : IBookRepository
{
     LibraryDBContext _db = new LibraryDBContext();

     public Book GetBookByIsbn(string isbn)
     {
         return _db.Books.Single(b => b.ISBN == isbn);
     }

     // And the rest of the data access
}
55
Eric King

これは私が行ってきた方法ですが、実装を交換できるように、データプロバイダーを汎用データサービスインターフェイスとして挿入しています。

私の知る限りでは、コントローラーは、データを取得し、アクションを実行し、データをビューに渡すためのものです。

2
Nathan Craddock