Linq .NET 5 中的 DatePart 函数使用可变间隔

DatePart function in Linq .NET 5 using variable interval

对于 EF Core 5,应该使用 SqlFunctionExpression 构造来使用 DatePart 函数,如下所示:

public int? DatePart(string datePartArg, DateTime? date) => throw new InvalidOperationException($"{nameof(DatePart)} cannot be called client side.");

protected override void OnModelCreating(ModelBuilder builder)
        {
            var methodInfo = typeof(DbFunctionExtensions).GetMethod(nameof(DatePart));

            var datePartMethodInfo = typeof(NotificationDbContext) // Your DB Context
                .GetRuntimeMethod(nameof(NotificationDbContext.DatePart), new[] { typeof(string), typeof(DateTime) });
            builder.HasDbFunction(datePartMethodInfo)
               .HasTranslation(args =>
                        new SqlFunctionExpression("DATEPART",
                            new[]
                            {
                            new SqlFragmentExpression((args.ToArray()[0] as SqlConstantExpression).Value.ToString()),
                            args.ToArray()[1]
                            },
                            true,
                            new[] { false, false },
                            typeof(int?),
                            null
                        )
                    );
        }

之后我们可以这样调用

_context.DatePart("day", x.Date);

但是我们如何传递变量而不是像下面这样的静态“天数”

string daysInterval="day";
_context.DatePart(daysInterval, x.Date);

daysInterval 将由一个根据条件返回年、月或日的函数初始化。那么我们如何才能通用地传递 daysInterval 而不是对其进行硬编码呢?

我认为这是不可能的,因为无法参数化 DATEPART 的第一个参数。 EG SQL 看起来像:

select datepart(day,getdate())

没有

select datepart('day',getdate())

和这个查询

_context.DatePart(daysInterval, x.Date);

将使用 daysInterval 的参数进行翻译。 AFAIK 要做到这一点,您是否必须转换查询表达式并用文字表达式动态替换变量表达式,这工作量太大了。

或提供您自己的 TSQL 标量函数,该函数的第一个参数为 varchar。喜欢

create function datepart2(@interval varchar(20), @d datetime2)
returns int
as
begin
  if @interval = 'day'
    return datepart(day,@d)
  else if @interval = 'second'
    return datepart(second,@d)
  --. . .

  return -1
end

然后这样注册:

modelBuilder.HasDbFunction(datePartMethodInfo)
   .HasTranslation(args =>
            new SqlFunctionExpression("dbo.DATEPART2",
                new[]
                {
                    args.ToArray()[0],
                    args.ToArray()[1]
                },
                true,
                new[] { false, false },
                typeof(int?),
                null
            )
        );