【发布时间】:2011-12-07 19:19:19
【问题描述】:
我正处于重构周期的中间,我转换了一些过去看起来像这样的扩展方法:
public static IQueryable<Family> FilterOnRoute(this IQueryable<Family> families, WicRoute route)
{
return families.Where(fam => fam.PODs
.Any(pod => pod.Route.RouteID == route.RouteID));
}
像这样更流畅的实现:
public class SimplifiedFamilyLinqBuilder
{
private IQueryable<Family> _families;
public SimplifiedFamilyLinqBuilder Load(IQueryable<Family> families)
{
_families = families;
return this;
}
public SimplifiedFamilyLinqBuilder OnRoute(WicRoute route)
{
_families = _families.Where(fam => fam.PODs
.Any(pod => pod.Route.RouteID == route.RouteID));
return this;
}
public IQueryable<Family> AsQueryable()
{
return _families;
}
}
我可以这样称呼:(注意这是使用 Linq-to-Nhibernate)
var families =
new SimplifiedFamilyLinqBuilder()
.Load(session.Query<Family>())
.OnRoute(new WicRoute() {RouteID = 1})
.AsQueryable()
.ToList();
这会产生以下 SQL,这对我来说很好:(值得注意的是上面的 Linq 正在被转换为 SQL 查询)
select ... from "Family" family0_
where exists (select pods1_.PODID from "POD" pods1_
inner join Route wicroute2_ on pods1_.RouteID=wicroute2_.RouteID
where family0_.FamilyID=pods1_.FamilyID
and wicroute2_.RouteID=@p0);
@p0 = 1
我的下一个重构工作是将处理孩子的查询部分移动到另一个类,如下所示:
public class SimplifiedPODLinqBuilder
{
private IQueryable<POD> _pods;
public SimplifiedPODLinqBuilder Load(IQueryable<POD> pods)
{
_pods = pods;
return this;
}
public SimplifiedPODLinqBuilder OnRoute(WicRoute route)
{
_pods = _pods.Where(pod => pod.Route.RouteID == route.RouteID);
return this;
}
public IQueryable<POD> AsQueryable()
{
return _pods;
}
}
将 SimplifiedFamilyLinqBuilder 更改为:
public SimplifiedFamilyLinqBuilder OnRoute(WicRoute route)
{
_families = _families.Where(fam =>
_podLinqBuilder.Load(fam.PODs.AsQueryable())
.OnRoute(route)
.AsQueryable()
.Any()
);
return this;
}
只有我现在得到这个错误:
Remotion.Linq.Parsing.ParserException:无法解析表达式“值(Wic.DataTests.LinqBuilders.SimplifiedPODLinqBuilder)”,因为它具有不受支持的类型。只能解析查询源(即实现 IEnumerable 的表达式)和查询运算符。
我开始在 SimplifiedPODLinqBuilder 上实现 IQueryable(因为这似乎比实现 IEnumberable 更合乎逻辑)并认为这样做会很聪明:
public class SimplifiedPODLinqBuilder : IQueryable
{
private IQueryable<POD> _pods;
...
public IEnumerator GetEnumerator()
{
return _pods.GetEnumerator();
}
public Expression Expression
{
get { return _pods.Expression; }
}
public Type ElementType
{
get { return _pods.ElementType; }
}
public IQueryProvider Provider
{
get { return _pods.Provider; }
}
}
只是为了得到这个异常(显然 Load 没有被调用并且 _pods 为空):
System.NullReferenceException : 对象引用未设置为对象的实例。
有没有办法让我重构这段代码,将其正确解析为将转到 SQL 的表达式?
【问题讨论】:
标签: linq linq-to-nhibernate fluent