[解決済み] 汎用リポジトリを作成する利点と、各オブジェクトに固有のリポジトリを作成する利点は何ですか?
質問
ASP.NET MVCアプリケーションを開発しており、現在、リポジトリ/サービスクラスを構築しています。 すべてのリポジトリが実装する汎用 IRepository インターフェースを作成することと、各リポジトリが独自のインターフェイスとメソッドのセットを持つことの間に、何か大きな利点があるのかどうか疑問に思っています。
たとえば、一般的な IRepository インターフェースは次のようになります(以下から引用)。 この回答 ):
public interface IRepository : IDisposable
{
T[] GetAll<T>();
T[] GetAll<T>(Expression<Func<T, bool>> filter);
T GetSingle<T>(Expression<Func<T, bool>> filter);
T GetSingle<T>(Expression<Func<T, bool>> filter, List<Expression<Func<T, object>>> subSelectors);
void Delete<T>(T entity);
void Add<T>(T entity);
int SaveChanges();
DbTransaction BeginTransaction();
}
各リポジトリは、例えばこのインターフェイスを実装することになります。
- カスタマーリポジトリ:IRepository
- プロダクトリポジトリ:IRepository
- その他
先行プロジェクトで踏襲してきたオルタネートなら
public interface IInvoiceRepository : IDisposable
{
EntityCollection<InvoiceEntity> GetAllInvoices(int accountId);
EntityCollection<InvoiceEntity> GetAllInvoices(DateTime theDate);
InvoiceEntity GetSingleInvoice(int id, bool doFetchRelated);
InvoiceEntity GetSingleInvoice(DateTime invoiceDate, int accountId); //unique
InvoiceEntity CreateInvoice();
InvoiceLineEntity CreateInvoiceLine();
void SaveChanges(InvoiceEntity); //handles inserts or updates
void DeleteInvoice(InvoiceEntity);
void DeleteInvoiceLine(InvoiceLineEntity);
}
2番目のケースでは、式(LINQまたはその他)は完全にリポジトリ実装に含まれ、サービスを実装する人はどのリポジトリ関数を呼び出すかを知る必要があるだけです。
サービスクラスですべての式の構文を書いて、リポジトリに渡すことの利点がわからないのでしょう。 これは、多くの場合、混乱しやすいLINQコードが重複していることを意味しませんか?
例えば、私たちの古い請求書作成システムでは、私たちは以下のように呼び出します。
InvoiceRepository.GetSingleInvoice(DateTime invoiceDate, int accountId)
をいくつかの異なるサービス(Customer, Invoice, Account, etc.)から呼び出すことができます。 以下のように複数の場所に書くより、ずっとすっきりしているように思います。
rep.GetSingle(x => x.AccountId = someId && x.InvoiceDate = someDate.Date);
特定のアプローチを使用する唯一の欠点は、Get*関数の多くの並べ替えに行き着くことですが、これは式ロジックをServiceクラスに押し上げるよりもまだ望ましいように思われます。
私は何を見逃しているのでしょうか?
どのように解決するのですか?
これは、Repositoryパターンそのものと同じくらい古い問題です。最近導入されたLINQの
IQueryable
の導入は、クエリの統一された表現であり、まさにこのトピックについて多くの議論を引き起こしました。
私自身は、汎用リポジトリフレームワークを構築するのに非常に苦労した後、特定のリポジトリを好んでいます。どのような巧妙なメカニズムを試しても、常に同じ問題に行き着きました。リポジトリはモデル化されたドメインの一部であり、そのドメインは一般的ではありません。すべてのエンティティが削除できるわけではなく、すべてのエンティティが追加できるわけでもなく、すべてのエンティティがリポジトリを持っているわけでもないのです。リポジトリ API は、エンティティそのものと同様にユニークになります。
私がよく使うパターンは、特定のリポジトリインターフェースを持ち、その実装のための基底クラスを持つことです。例えば、LINQ to SQLを使用すると、次のようになります。
public abstract class Repository<TEntity>
{
private DataContext _dataContext;
protected Repository(DataContext dataContext)
{
_dataContext = dataContext;
}
protected IQueryable<TEntity> Query
{
get { return _dataContext.GetTable<TEntity>(); }
}
protected void InsertOnCommit(TEntity entity)
{
_dataContext.GetTable<TEntity>().InsertOnCommit(entity);
}
protected void DeleteOnCommit(TEntity entity)
{
_dataContext.GetTable<TEntity>().DeleteOnCommit(entity);
}
}
置換
DataContext
をお好みの単位に置き換えてください。実装例としては、以下のようになります。
public interface IUserRepository
{
User GetById(int id);
IQueryable<User> GetLockedOutUsers();
void Insert(User user);
}
public class UserRepository : Repository<User>, IUserRepository
{
public UserRepository(DataContext dataContext) : base(dataContext)
{}
public User GetById(int id)
{
return Query.Where(user => user.Id == id).SingleOrDefault();
}
public IQueryable<User> GetLockedOutUsers()
{
return Query.Where(user => user.IsLockedOut);
}
public void Insert(User user)
{
InsertOnCommit(user);
}
}
リポジトリの公開APIは、ユーザーの削除を許可していないことに注意してください。また、公開された
IQueryable
を公開することは、まったく別の問題です。この話題については、おへそのボタンと同じくらい多くの意見があります。
関連
-
ASP.NET Core 6で依存関係を解決する3つの方法
-
NET6新機能 新構造体の最適化
-
認証プロセスの記録にjwtを使用したネット
-
[解決済み] web.configでmaxJsonLengthの長さを無制限に設定することは可能ですか?
-
[解決済み] ASP.NET MVC - カスタムIIdentityまたはIPrincipalの設定
-
[解決済み] ASP.NET MVCコントローラは、Imageを返すことができますか?
-
[解決済み】ASP.NET Bundles ミニフィケーションを無効にする方法
-
[解決済み] web.configの変換で "Replace Or Insert "を行う方法はありますか?
-
[解決済み] Log4netがログファイルにログを書き込まない
-
[解決済み] WatiNかSeleniumか?[クローズド]
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
ASP.NET Core MVC Dependency Injection ビューとコントローラ
-
Net CoreによるAutoFacの利用
-
403 - アクセス拒否。IIS7 でファイルを開くと、アクセス拒否されます。
-
CS0234 名前空間 'Microsoft.AspNet' に型または名前空間名 'Mvc' が存在しない (あなたは
-
[解決済み] ASP.NET MVCでビューをコンパイルする
-
[解決済み] カタナ」と「オウイン」をわかりやすく説明すると?
-
[解決済み】ASP.NET Bundles ミニフィケーションを無効にする方法
-
[解決済み】ASP.NET IdentityのIUserSecurityStampStore<TUser>インターフェースとは何ですか?
-
[解決済み] ASP.NET MVCのAjaxポストでantiforgerytokenを含める。
-
[解決済み] Log4netがログファイルにログを書き込まない