私はあなたのリポジトリにORMを使用している場合、それはすでにデータベースから十分に抽象化されていると信じています。
ただし、私が現在作業している場合、後でORMを変更する場合に備えて、ORMを抽象化するレイヤーが必要だと誰かが信じています。
多くのORMで機能するレイヤーを作成することは本当に必要ですか、それとも単純に多くのオーバーヘッドがありますか?
詳細を説明するために:
その方法は狂気です。 ORMを変更する必要が生じることはほとんどありません。また、ORMを変更することを決定した場合、マッピングを書き換えるコストは、独自のメタORMを開発および維持するためのコストのほんの一部です。 ORMを切り替えるために必要な作業の95%を実行するスクリプトをいくつか記述できると思います。
社内のフレームワークはほとんど常に災害です。将来のニーズを見越して1つを構築することは、ほぼ保証された災害です。成功するフレームワークは、架空のニーズを満たすために事前に構築されたのではなく、成功したプロジェクトから抽出されます。
ORMは、データレイヤーをRDBMSから独立させるための抽象化を提供しますが、ビジネスレイヤーをデータレイヤーから「切り離す」には不十分な場合があります。具体的には、RDBMSテーブルにマップするオブジェクトがビジネスレイヤーに直接「リーク」しないようにする必要があります。
少なくとも、ビジネスレイヤーは、データレイヤーのORM管理のテーブルマップオブジェクトが実装する可能性のあるインターフェイスにプログラムする必要があります。さらに、ORMのネイティブクエリ機能を非表示にするために、抽象クエリ構築のインターフェイスベースのレイヤーを作成する必要がある場合があります。主な目標は、特定のORMがデータレイヤーを超えてソリューションに組み込まれるのを回避することです。たとえば、ビジネスレイヤーにHQL(Hibernate Query Language)文字列を作成するのは魅力的です。ただし、この一見無害な決定では、ビジネスレイヤーをHibernateに結び付け、ビジネスレイヤーとデータアクセスレイヤーを一緒に釘付けにします。この状況をできるだけ回避する必要があります。
EDIT:この場合、リポジトリ内の追加のレイヤーは時間の無駄です。ポイント2に基づいて、ビジネスレイヤーはリポジトリから十分に隔離されています。追加の断熱材を提供すると、不必要な複雑さが生じ、追加の利点はありません。
リポジトリ内に追加の抽象化レイヤーを構築することの問題は、ORMの特定の「ブランド」が、それとの対話方法を決定することです。 ORMのように見えるが、自分の管理下にある薄いラッパーを構築する場合、基になるORMを置き換えるのは、追加のレイヤーがない場合と同じくらい困難です。一方、ORMのように見えないレイヤーを作成する場合は、オブジェクトリレーショナルマッピングテクノロジーの選択に疑問を投げかける必要があります。
UnitOfWorkは通常、この抽象化を提供します。これは変更が必要な場所の1つであり、リポジトリはインターフェースを介してそれに依存します。 O/RMを変更する必要がある場合は、その上に新しいUoWを実装してください。 1つ完了しました。
ところで、それは単にO/RMを切り替えるだけではありません。単体テストについて考えてみてください。私は3つのUnitOfWork実装を持っています。1つはEF用、もう1つはNH用です(実際にはDID Oracleサポートを必要とするクライアントのプロジェクトの途中でO/RMを切り替える必要があるため)、および1つはInMemory永続性のためです。 。データベースを背後に配置する準備が整う前に、InMemory永続性は単体テストやラピッドプロトタイピングにも最適でした。
フレームワークは実装が簡単です。まず、一般的なIRepositoryインターフェイスがあります
public interface IRepository<T>
where T:class
{
IQueryable<T> FindBy(Expression<Func<T,Bool>>filter);
IQueryable<T> GetAll();
T FindSingle(Expression<Func<T,Bool>> filter);
void Add(T item);
void Remove(T item);
}
そして、IUnitOfWorkインターフェース
public interface IUnitOfWork
{
IQueryable<T> GetSet<T>();
void Save();
void Add<T>(T item) where T:class;
void Remove<T>(T item) where T:class;
}
次はベースリポジトリです(抽象にするかどうかの選択)
public abstract class RepositoryBase<T>:IRepository<T>
where T:class
{
protected readonly IUnitOfWork _uow;
protected RepositoryBase(IUnitOfWork uow)
{
_uow=uow;
}
public IQueryable<T> FindBy(Expression<Func<T,Bool>>filter)
{
return _uow.GetSet<T>().Where(filter);
}
public IQueryable<T> GetAll()
{
return _uow.GetSet<T>();
}
public T FindSingle(Expression<Func<T,Bool>> filter)
{
return _uow.GetSet<T>().SingleOrDefault(filter);
}
public void Add(T item)
{
return _uow.Add(item);
}
public void Remove(T item)
{
return _uow.Remove(item);
}
}
IUnitOfWorkの実装は、EF、NH、およびIn Memoryの子供の遊びです。私がIQueryableを返す理由は同じ理由です、とAyendeは彼の投稿で述べました、クライアントはLINQを使用して結果をさらにフィルタリング、並べ替え、グループ化、さらには投影することができ、サーバーサイドで行われるすべての利点を引き続き利用できます。