У меня есть поисковый репозиторий для EntityFramework 4.0, использующий LinqKit со следующей функцией поиска:
public IQueryable<T> Search<T>(Expression<Func<T, bool>> predicate)
where T : EntityObject
{
return _unitOfWork.ObjectSet<T>().AsExpandable().Where(predicate);
}
И другой класс, который использует возвращаемое значение IQueryable для поднабора запроса способами, которые не возможны с использованием логического значенияВыражения LinqKit PredicateBuilder:
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);
}
Проблема здесь в том, что «T» как EntityObject не определяет GUID, поэтому я не могу использовать это.Естественным ответом на это является определение метода SubsetByUser () для использования ограничения со свойством GUID:
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 (). Есть ли какой-нибудь способ, которым я могу собрать это вместе, что мне не хватает?