【发布时间】:2012-02-25 14:17:12
【问题描述】:
我有一个使用具有以下搜索功能的 LinqKit 的 EntityFramework 4.0 搜索存储库:
public IQueryable<T> Search<T>(Expression<Func<T, bool>> predicate)
where T : EntityObject
{
return _unitOfWork.ObjectSet<T>().AsExpandable().Where(predicate);
}
另一个类使用 IQueryable 返回值以使用 Boolean 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' as 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() 返回它,我似乎无能为力。有什么方法可以把我错过的这些放在一起吗?
【问题讨论】:
-
是否可以显示更多关于您如何使用此 SubsetByUser 函数的代码(您将从查询中调用它)。尝试做类似的事情。
-
@AaronLS,我不再参与这个项目,但基本上——IIRC,set 参数是另一个查询的返回集。所以它只是 _subsetContainer.SubsetByUser
(_container.Search (predicate), someUser);
标签: linq entity-framework linq-to-entities iqueryable linqkit