Czołem
Zgodnie z tym artykułem https://learn.microsoft.com/en-us/ef/core/querying/user-defined-function-mapping próbowałem zmapować do EF najpierw wbudowaną funkcję SQL Server tj DATENAME.
public string DateName(string arg, DateTime date) => throw new InvalidOperationException($"{nameof(DateName)} cannot be called client side.");
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
var dateNameMethodInfo = typeof(DbContext)
.GetRuntimeMethod(nameof(DbContext.DateName), new[] { typeof(string), typeof(DateTime) });
builder.HasDbFunction(dateNameMethodInfo)
.HasTranslation(args =>
new SqlFunctionExpression("DATENAME",
new[]
{
new SqlFragmentExpression((args.ToArray()[0] as SqlConstantExpression).Value.ToString()),
args.ToArray()[1]
},
true,
new[] { false, false },
typeof(string),
null));
}
Niestety, ale dla powyższego sposobu dostaję wyjątek:
The LINQ expression 'DbSet<WorkingDay>()
.Where(n => ___dbContext_0.DateName(
arg: "weekday",
date: n.WorkingDayDate) == "Monday")' could not be translated. Additional information: Translation of method 'Chancellor.Application.Common.DbContexts.IChancellorDbContext.DateName' failed. If this method can be mapped to your custom function, see https://go.microsoft.com/fwlink/?linkid=2132413 for more information. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
Zrobiłem też dokładnie tak jak w przytoczonym artukule tj opakowałem DATENAME w moją funkcję WrappedDateName
CREATE FUNCTION [dbo].[WrappedDateName](@date DATE, @returnType VARCHAR(10))
RETURNS VARCHAR(9)
AS
BEGIN
IF (@returnType = 'weekday')
RETURN DATENAME(weekday, @date);
RETURN NULL;
END
Następnie dodałem mapowanie na metodę i translację:
public string DateName(string arg, DateTime date) => throw new InvalidOperationException($"{nameof(DateName)} cannot be called client side.");
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.HasDbFunction(trDbContext).GetMethod(nameof(DateName), new[] { typeof(string), typeof(DateTime) }))
.HasName("WrappedDateName");
}
builder.HasDbFunction(typeof(ChancellorDbContext).GetMethod(nameof(DateName), new[] { typeof(string), typeof(DateTime) }))
.HasName("WrappedDateName");
Dostaję wyjątek:
The LINQ expression 'DbSet<WorkingDay>()
.Where(n => ___dbContext_0.DateName(
arg: "weekday",
date: n.WorkingDayDate) == "Monday")' could not be translated. Additional information: Translation of method 'Chancellor.Application.Common.DbContexts.IChancellorDbContext.DateName' failed. If this method can be mapped to your custom function, see https://go.microsoft.com/fwlink/?linkid=2132413 for more information. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
W drugim przypadku robię identycznie jak w artykule MS.
Ktoś może podpowiedzieć jak to zrobić aby działało?
Nie chcę pobierać zestawu do pamięci i robić porównanie po stronie aplikacji skoro Sql Server ma taką funkcję wbudowaną.