我有一个类似这样的查询。
var railcars = DbContext.Railcars
.Select(r => new
{
Number = r.RailcarNumber,
Quantity = railcar.InboundQuantity
- DbContext.Transfers
.Where(t => t.FromType == TransferType.Railcar && t.FromId == railcar.Id)
.Sum(t => t.Quantity)
+ DbContext.Transfers
.Where(t => t.ToType == TransferType.Railcar && t.ToId == railcar.Id)
.Sum(t => t.Quantity)
};
Quantity
的计算有点复杂,我会在很多不同的地方使用这个计算。所以我想稍微简化一下这个语法。我真正想做的是创建我自己的函数并将其转换为 SQL,如下所示。
public static class QueryHelper
{
public static double GetCurrentQuantity(this Railcar railcar, ApplicationDbContext dbContext)
{
throw new InvalidOperationException("This method cannot be executed directly.");
}
}
var railcars = DbContext.Railcars
.Select(r => new
{
Number = r.RailcarNumber,
Quantity = QueryHelper.GetCurrentQuantity(r, DbContext)
};
我一直在研究使用
IMethodCallTranslator
将所需代码转换为 SQL。但我能找到的唯一示例似乎很旧,例如,IMethodCallTranslator.Translate()
的调用签名完全不同。
另外,我不知道如何创建一个像我需要的那样复杂的表达式到
SqlExpression
中(这就是 Translate()
方法返回的内容)。
问题:
SqlExpression
这个综合体的任何示例或文档吗?是的,通过构建要在查询中执行的 Fn 应该可以实现类似的操作。
private Func<Railcar, int> BuildQuantity(SoftDeleteDbContext context)
{
return (Railcar r) => {
return context.Transfers.Where(t => t.TransferToType == "RC" && t.TransferToId == r.RailcarId)
.Sum(t => t.Quantity)
- context.Transfers.Where(t => t.TransferFromType == "RC" && t.TransferFromId == r.RailcarId)
.Sum(t => t.Quantity); };
}
然后在构建查询时:
var query = context.Railcars
.Select(x => new
{
x.RailcarId,
x.Name,
Quantity = startingQuantity
+ BuildQuantity(context)(x)
});
如果使用单个注入的 DbContext 实例,则可能不需要传递 DbContext,但如果您使用的是作用域实例或 UoW 模式,则可能有必要。您也可以将startingQuantity注入到方法本身中。我刚刚测试了到目前为止,得到了与手动解析相同的结果。
请注意,我只建议在单个轨道车或小型列车上运行这样的构造。如果跨整个集合运行,您可能会遇到明显的性能问题,因为它在事务表中进行两次子查询。