次の検索機能を備えたLinqKitを使用したEntityFramework4.0の検索リポジトリがあります。
public IQueryable<T> Search<T>(Expression<Func<T, bool>> predicate)
where T : EntityObject
{
return _unitOfWork.ObjectSet<T>().AsExpandable().Where(predicate);
}
また、IQueryableの戻り値を使用して、ブール値のLinqKitPredicateBuilder式では不可能な方法でクエリをサブセット化する別のクラス:
public IQueryable<T> SubsetByUser<T>(IQueryable<T> set, User user)
where T : EntityObject
{
return set.Join(_searcher.Search<Metadatum>((o) => o.UserGUID == user.GUID),
arc => arc.GUID,
meta => meta.ElementGUID,
(arc, meta) => arc);
}
ここでの問題は、EntityObjectとしての「T」がGUIDを定義していないため、これを使用できないことです。これに対する自然な応答は、GUIDプロパティで制約を使用するようにSubsetByUser()メソッドを実際に定義することです。
public IQueryable<T> SubsetByUser<T>(IQueryable<T> set, User user)
where T : IHaveMetadata
{
return set.Join(_searcher.Search<Metadatum>((o) => o.UserGUID == user.GUID),
arc => arc.GUID,
meta => meta.ElementGUID,
(arc, meta) => arc);
}
しかし、これは機能しません。LinqKitを使用していますが、Expandable()メソッドの結果は次のようになります。
System.NotSupportedException: Unable to cast the type 'Oasis.DataModel.Arc' to
type 'Oasis.DataModel.Interfaces.IHaveMetadata'. LINQ to Entities only supports
casting Entity Data Model primitive types
IQueryableを返す必要があります。私はこのような偽物をすることができます:
public IQueryable<T> SubsetByUser<T>(IQueryable<T> set, User user)
where T : EntityObject
{
return set.AsEnumerable()
.Join(_searcher.Search<Metadatum>((o) => o.UserGUID == user.GUID),
arc => arc.GUID,
meta => meta.ElementGUID,
(arc, meta) => arc)
.AsQueryable();
}
もちろん、これは機能しますが、もちろん、これは非常にクレイジーなことでもあります。(IQueryableが必要な理由は、最終的になるまでクエリを実行しないためです。
私もこれを試しました:
public IQueryable<T> SubsetByUser<T>(IQueryable<T> set, User user)
where T : EntityObject
{
return set.Join(_searcher.Search<Metadatum>((o) => o.UserGUID == user.GUID),
arc => arc.GetType().GetProperty("GUID").GetValue(arc,null),
meta => meta.ElementGUID,
(arc, meta) => arc);
}
これは、リフレクションを使用してRunsコレクションを取得し、コンパイラエラーを回避します。それはかなり賢いと思いましたが、LINQ例外が発生します。
System.NotSupportedException: LINQ to Entities does not recognize the
method 'System.Object GetValue(System.Object, System.Object[])' method,
and this method cannot be translated into a store expression.
検索方法を変更することもできます。
public IQueryable<T> Search<T>(Expression<Func<T, bool>> predicate)
where T : IRunElement
{
return _unitOfWork.ObjectSet<T>().AsExpandable().Where(predicate);
}
ただし、IRunElementはEntityObjectではなく、ObjectSetはTをクラスとして制約するため、これはもちろんコンパイルされません。
最後の可能性は、単にすべてのパラメーターと戻り値をIEnumerableにすることです。
public IEnumerable<T> SubsetByUser<T>(IEnumerable<T> set, User user)
where T : EntityObject
{
return set.Join(_searcher.Search<Metadatum>((o) => o.UserGUID == user.GUID),
arc => arc.GetType().GetProperty("GUID").GetValue(arc,null),
meta => meta.ElementGUID,
(arc, meta) => arc);
}
これも機能しますが、これもインスタンス化を最後まで遅らせることはできません。
したがって、すべてをIEnumerableとしてインスタンス化し、AsQueryable()を使用して返すことなく、この作業を行うためにできることはほとんどないようです。私が欠けているこれをまとめることができる方法はありますか?