我正在尝试手动组合表达式树以实现某种程度的模块化,这似乎暗示我使用标准的 linq 运算符。该代码本质上创建了一个表达式树,它使用一个表达式来决定调用另外两个表达式中的哪一个。其他表达式之一需要一个额外的参数,该参数本身是使用另一个表达式获得的。此参数用于获取多个值,但对于每次访问,检索参数的表达式都会重复。我已经包含了代码和输出以更好地解释:
public void Test() {
var parameters = ProjectionOne.Parameters;
Expression<Func<Foo, bool>> isType = f => f.TypeId == 1;
Expression<Func<Foo, Satellite>> satSelector = f => f.Satellites.Single();
var satelliteSelector = Expression.Invoke(satSelector, parameters[0]);
var test = Expression.Lambda<Func<Foo, Bar>>(
Expression.Condition(
Expression.Invoke(isType, parameters[0]),
Expression.Invoke(ProjectionOne, parameters[0]),
Expression.Invoke(ProjectionTwo, parameters[0], satelliteSelector)), parameters);
}
public Expression<Func<Foo, Bar>> ProjectionOne {
get {
return foo => new Bar() {
Id = foo.Id
};
}
}
public Expression<Func<Foo, Satellite, Bar>> ProjectionTwo {
get {
return (foo, sat) => new Bar() {
Id = foo.Id,
Start = sat.Start,
End = sat.End
};
}
}
当我在数据库上运行此查询时,生成的 SQL 如下:
SELECT [t0].[value], [t0].[value2] AS [Start], [t0].[value3] AS [End], [t0].[Id] AS [Id]
FROM (
SELECT
(CASE
WHEN [t0].[TypeId] = @p0 THEN 1
WHEN NOT ([t0].[TypeId] = @p0) THEN 0
ELSE NULL
END) AS [value], (
SELECT [t2].[Start]
FROM [dbo].[Satellite] AS [t2]
WHERE [t2].[Id] = [t0].[Id]
) AS [value2], (
SELECT [t2].[End]
FROM [dbo].[Satellite] AS [t2]
WHERE [t2].[Id] = [t0].[Id]
) AS [value3], [t0].[Id]
FROM [dbo].[Foo] ) AS [t0]
问题是重复的子选择。一个检索“开始”值,而另一个检索“结束”值。如果它们都从单个子选择中检索出来会更好。如何更改表达式树的构造以强制执行此操作?此外,我确实了解执行此查询有更简单的方法,但是它是此处未显示的更大框架的一部分,只能通过能够从大量可重用表达式中手动组装表达式树来实现。