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
)
);
对于 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
)
);