使用 IMethodCallTranslator 编写自定义实体框架函数

问题描述 投票:0回答:1

我有一个类似这样的查询。

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()
方法返回的内容)。

问题:

  1. 有谁知道可以吗?我走在正确的道路上吗?
  2. 有什么好的例子吗?
  3. 有关于构建
    SqlExpression
    这个综合体的任何示例或文档吗?
  4. 有什么具体逻辑的例子可以帮助我开始吗?
c# .net entity-framework .net-core entity-framework-core
1个回答
0
投票

是的,通过构建要在查询中执行的 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注入到方法本身中。我刚刚测试了到目前为止,得到了与手动解析相同的结果。

请注意,我只建议在单个轨道车或小型列车上运行这样的构造。如果跨整个集合运行,您可能会遇到明显的性能问题,因为它在事务表中进行两次子查询。

© www.soinside.com 2019 - 2024. All rights reserved.