回答:
リポジトリ層は、データアクセスに対する追加レベルの抽象化を提供します。書く代わりに
var context = new DatabaseContext();
return CreateObjectQuery<Type>().Where(t => t.ID == param).First();
データベースから単一のアイテムを取得するには、リポジトリインターフェイスを使用します
public interface IRepository<T>
{
IQueryable<T> List();
bool Create(T item);
bool Delete(int id);
T Get(int id);
bool SaveChanges();
}
そしてを呼び出しますGet(id)
。リポジトリ層は、基本的なCRUD操作を公開します。
サービス層は、リポジトリを使用するビジネスロジックを公開します。サービスの例は次のようになります。
public interface IUserService
{
User GetByUserName(string userName);
string GetUserNameByEmail(string email);
bool EditBasicUserData(User user);
User GetUserByID(int id);
bool DeleteUser(int id);
IQueryable<User> ListUsers();
bool ChangePassword(string userName, string newPassword);
bool SendPasswordReminder(string userName);
bool RegisterNewUser(RegisterNewUserModel model);
}
一方でList()
、すべてのユーザーが、リポジトリリターンの方法ListUsers()
IUserServiceのが唯一のものを返すことができ、ユーザーはへのアクセス権を持っています。
ASP.NET MVC + EF + SQL SERVERでは、次の通信フローがあります。
ビュー<-コントローラー->サービスレイヤー->リポジトリレイヤー-> EF-> SQL Server
サービス層->リポジトリ層-> EFこの部分はモデルで動作します。
ビュー<-コントローラ->サービス層このパーツはビューモデルで動作します。
編集:
/ Orders / ByClient / 5のフローの例(特定のクライアントの注文を確認したい):
public class OrderController
{
private IOrderService _orderService;
public OrderController(IOrderService orderService)
{
_orderService = orderService; // injected by IOC container
}
public ActionResult ByClient(int id)
{
var model = _orderService.GetByClient(id);
return View(model);
}
}
これは注文サービスのインターフェースです:
public interface IOrderService
{
OrdersByClientViewModel GetByClient(int id);
}
このインターフェースはビューモデルを返します。
public class OrdersByClientViewModel
{
CientViewModel Client { get; set; } //instead of ClientView, in simple project EF Client class could be used
IEnumerable<OrderViewModel> Orders { get; set; }
}
これはインターフェースの実装です。モデルクラスとリポジトリを使用してビューモデルを作成します。
public class OrderService : IOrderService
{
IRepository<Client> _clientRepository;
public OrderService(IRepository<Client> clientRepository)
{
_clientRepository = clientRepository; //injected
}
public OrdersByClientViewModel GetByClient(int id)
{
return _clientRepository.Get(id).Select(c =>
new OrdersByClientViewModel
{
Cient = new ClientViewModel { ...init with values from c...}
Orders = c.Orders.Select(o => new OrderViewModel { ...init with values from o...}
}
);
}
}
IRepository<>
しGenericRepository<>
て、IOCライブラリにバインドできます。この答えは非常に古いです。最善の解決策は、すべてのリポジトリをと呼ばれる1つのクラスに結合することですUnitOfWork
。すべてのタイプのリポジトリとと呼ばれる1つのメソッドが含まれている必要がありますSaveChanges
。すべてのリポジトリは1つのEFコンテキストを共有する必要があります。
Carnotaurusが言ったように、リポジトリはデータをストレージフォーマットからビジネスオブジェクトにマッピングする責任があります。ストレージとの間のデータの読み取りと書き込み(削除、更新も)の両方を処理する必要があります。
一方、サービス層の目的は、ビジネスロジックを単一の場所にカプセル化して、コードの再利用と問題の分離を促進することです。Asp.net MVCサイトを構築するとき、これが実際に私にとって通常意味することは、私がこの構造を持っているということです
[Controller]が[Service(s)]を呼び出し、[Repository(ies)]を呼び出す
私が有用であるとわかった1つの原則は、コントローラーとリポジトリーでロジックを最小限に抑えることです。
コントローラーでそれは私を乾燥した状態に保つのを助けるからです。同じフィルタリングまたはロジックを他の場所で使用する必要があることは非常に一般的であり、コントローラーに配置した場合、再利用できません。
リポジトリでは、何か良いものが来たときにストレージ(またはORM)を交換できるようにしたいからです。リポジトリにロジックがある場合、リポジトリを変更するときにこのロジックを書き換える必要があります。一方、リポジトリがIQueryableのみを返し、サービスがフィルタリングを行う場合、マッピングを置き換えるだけで済みます。
たとえば、私は最近、Linq-To-SqlリポジトリのいくつかをEF4に置き換えました。この原則に忠実であったリポジトリは、ほんの数分で置き換えられる可能性があります。私が何らかの論理を持っているところでは、代わりに数時間の問題でした。
onBeforeBuildBrowseQuery
、クエリビルダーを使用してクエリを変更できる場所を考えています。
受け入れられた回答(そして何百回も賛成)には大きな欠陥があります。私はコメントでこれを指摘したかったのですが、30のコメントで埋められるので、ここで指摘します。
そのように構築されたエンタープライズアプリケーションを引き継ぎ、私の最初の反応はWTHでしたか?サービスレイヤーのViewModels?何年も開発が進んでいたため、私は規約を変更したくなかったので、ViewModelsを返し続けました。WPFを使い始めたとき、それは悪夢に変わりました。私たち(開発チーム)はいつも言っていました:どのViewModelですか?実際のもの(WPF用に作成したもの)またはサービスのもの これらはWebアプリケーション用に作成され、UIでの編集を無効にするためのIsReadOnlyフラグさえありました。メジャー、メジャーな欠陥、そしてすべて1つの単語:ViewModel !!
同じ間違いをする前に、上記の私の話に加えて、いくつかの理由があります。
サービスレイヤーからViewModelを返すのは非常に困難です。それは言っているようなものです:
これらのサービスを使用する場合は、MVVMを使用することをお勧めします。ここに、使用する必要のあるViewModelを示します。痛い!
サービスは、UIのどこかに表示されることを想定しています。WebサービスやWindowsサービスなどの非UIアプリケーションで使用されている場合はどうなりますか?
これは実際のViewModelでもありません。実際のViewModelには可観測性、コマンドなどがあります。これは、悪い名前のPOCOです。(名前が重要な理由については、上の私のストーリーを参照してください。)
使用するアプリケーションはプレゼンテーションレイヤー(ViewModelはこのレイヤーで使用されます)であり、C#をよく理解しています。別の痛い!
しないでください!
通常、リポジトリは、エンティティを設定するための足場として使用されます。サービスレイヤーは外に出て、リクエストをソースします。サービスレイヤーの下にリポジトリを配置する可能性があります。