使用する
- Visual Studio 2010
- .Net Framework 4
- C#
- エンティティへのLinq
問題
DRYやSOLIDなどのオブジェクト指向の原則をいくつかのLinqプロジェクションに適用できるようにしたいと思います。コンパイルされたクエリまたは渡されたパラメーターを使用して、これまでのところ、予測ではなく、Linqの残りの部分にこれらを正常に適用できます。
これが不可能な場合はお知らせください。可能な場合は、代替ソリューション(以下で説明)のいずれかを選択する必要があります。可能であれば、または何かが不足していて、目標を満たす別の代替実装がある場合。
詳細
大まかに言えば、標準のLinqクエリまたはCompiledQueryのいずれかを使用して、Linqプロジェクションで使用される型を動的に制御できるようにしたいと考えています。例と実際のコードではLinqtoEntitiesを使用していますが、この問題はコアLinqに当てはまるはずです。
以下は、動的ではなく、問題を解決しない単純な例です。タイプごとに常にFooUserを使用するように修正されています。私ができるようにしたいのは、プロジェクションで作成されたユーザーのタイプを動的に制御することです。これらはすべて、共通のIUserインターフェイスに基づいています。これは、クエリがフィルタリングするタイプを制御する方法と似ているか、似ている可能性があります。
代替ソリューション
私はDRY、SOLIDに準拠しようとしています。また、典型的なコードの臭いである列挙型を使用して対処することを避けようとしています。しかし、私のすべての試みと研究において、私は次の解決策の1つに陥らなければならないようです。
フィルタするタイプとプロジェクションで使用されるタイプを除いて、すべて同じタイプのクエリを実装します。これはDRYとOCPに違反しますが、これを1つのクラス内にカプセル化して、準拠したクエリとして互いに近づけることができます。これには、新しいタイプを追加した場合、またはデータのクエリ方法が変更された場合に、クラスを変更する必要があります。
タイプを持つ列挙型を実装し、そのタイプをプロパティとして持つ、より一般化されたUserクラスを使用します。ただし、これにより、いくつかの場所で列挙型を使用し、それらを処理するために長いケースステートメントを導入する必要があります。これは避けたいと思います。
さまざまな悪から選択する必要がなく、すべてのSOLIDの原則とDRYに準拠できる実装が必要です。しかし、私がしなければならない場合、私はそれの最初またはバージョンで終わると思います。
例
標準の単純なLinqクエリ
using (MyEntities context = new MyEntities())
{
var results = from u in context.Users
where u.UserType == type
select new FooUser
{
Id = u.UserID,
Name = u.UserName,
Location = u.UserLocation
};
}
上記のクエリのコンパイル済みバージョン
private static readonly Func<MyEntities, int, IQueryable<FooUser>> query = CompiledQuery.Compile<MyEntities, int, IQueryable<FooUser>>(
(context, type) => from u in context.Users
where u.UserType == type
select new FooUser
{
Id = u.UserID,
Name = u.UserName,
Location = u.UserLocation
});-