現在のリポジトリ メソッドの実装を改善することを考えてGetAll
おり、以下のコードを書きました。Google でそのようなアプローチのアイデアを見つけようとしましたが、成功しませんでした。コードを確認して、以下のいくつかの質問に答えてください。簡単な例を次に示します。
class Service
{
public void DoOperation()
{
// Let's say we need to retrieve users by criteria
var items = UnitOfWork
.Over<User>() // Get repository of User
.GetAll() // Start querying
// If we need simple WHERE then use:
.Where(x => x.Email == "some@email.com")
// If we need more complex condition then use specification:
.Using(new UserNameContains("John"))
// Execute:
.List();
}
}
class UnitOfWork
{
public Repository<T> Over<T>()
{
// Get from DI container or injected field
return new Repository<T>();
}
}
class Repository<T>
{
public QueryWrapper<T> GetAll()
{
return new QueryWrapper<T>(Session.QueryOver<T>());
}
}
class QueryWrapper<T>
{
// Query from DB session. Init from constructor.
private IQueryOver<T> _query;
public QueryWrapper<T> Where(Expression<Func<T, bool>> expression)
{
_query = _query.Where(expression);
return this;
}
public QueryWrapper<T> Using(Specification<T> spec)
{
var spec = new TSpec();
_query = spec.Apply(_query);
return this;
}
public IEnumerable<T> List()
{
return return _query.List();
}
}
abstract class Specification<T>
{
public abstract IQueryOver<T> Apply(IQueryOver<T> query);
}
class UserNameContains : Specification<User>
{
// Init from constructor:
private string _name;
public override IQueryOver<User> Apply(IQueryOver<User> query)
{
return /* apply filter condition here */;
}
}
その結果、次のようなメリットが得られます。
- カスタム Repos を作成する必要はもうありません。単一のジェネリックで十分です。
- カスタム仕様の実装がデータ層から分離され、テスト可能になりました。
- サービスから使いやすい。
- など
QueryWrapper
の追加のメソッドをサポートするために、常に拡張できます。OrderBy
- そして、それはまだ単体テスト可能です。
私のアプローチのリークを教えてください。または、問題のビジョンを教えてください。また、既存の記事へのリンクも素晴らしいでしょう。