I'm using Postgresql with EF Core 3.1 on my ASP.NET project
I want to generate a sql fragment like this:
EXTRACT(EPOCH FROM TIMESTAMP WITH TIME ZONE f."MyDateTimeField")"
So, I have writed this code on OnModelCreating method of the DbContext:
modelBuilder
.HasDbFunction(typeof(MyDbFunctions).GetMethod(
nameof(MyDbFunctions.ExtractEpochFromTimestampWithTimezone)))
.HasTranslation(args
=> SqlFunctionExpression.Create(
"EXTRACT",
new []
{
new SqlFragmentExpression(
$"EPOCH FROM TIMESTAMP WITH TIME ZONE"),
args.First()
}, typeof(double), null));
But the generated SQL fragment was:
EXTRACT(EPOCH FROM TIMESTAMP WITH TIME ZONE, f."MyDateTimeField")
Note that SQL has one "," after word "ZONE".
How can I fix my code to generate the SQL fragment without this ","?
Any one that faced same issues as above. I have solve above issue with the following code
Test entity
public class Employee
{
public int Id { get; set; }
public DateTime DOB { get; set; }
public string Name { get; set; }
}
EF Core Dbcontext with custom postgres EXTRACT function
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasDbFunction(ExtractMethod)
.HasTranslation(args =>
{
var arguments = args.ToList();
//{((Microsoft.EntityFrameworkCore.Query.SqlExpressions.ColumnExpression)arguments[1]).TypeMapping.StoreType}
arguments[0] = new SqlFragmentExpression($"{((Microsoft.EntityFrameworkCore.Query.SqlExpressions.SqlConstantExpression)arguments[0]).Value} from {((Microsoft.EntityFrameworkCore.Query.SqlExpressions.ColumnExpression)arguments[1]).Table.Alias}.\"{((Microsoft.EntityFrameworkCore.Query.SqlExpressions.ColumnExpression)arguments[1]).Name}\"");
arguments.RemoveAt(1);
return new SqlFunctionExpression("EXTRACT",
arguments,
false,
new bool[] { false, false},
typeof(decimal),
RelationalTypeMapping.NullMapping);
});
}
EF function which is mapped
private readonly MethodInfo ExtractMethod
= typeof(Context).GetRuntimeMethod(nameof(Extract), new[] { typeof(string), typeof(DateTime) });
public DateTime Extract(string field, DateTime source)
=> throw new NotSupportedException();
The above method will fail when using nested functions. I have updated it with proper implementaion. I hope this will help others
Added a new class called ExtractExpression
public class ExtractExpression:SqlFunctionExpression
{
private readonly IReadOnlyCollection<SqlExpression> _params;
public ExtractExpression(IReadOnlyCollection<SqlExpression> parameters):base("EXTRACT", true, typeof(double), RelationalTypeMapping.NullMapping)
{
_params = parameters;
}
protected override Expression Accept(ExpressionVisitor visitor)
{
if (!(visitor is QuerySqlGenerator))
return base.Accept(visitor);
visitor.Visit(new SqlFragmentExpression("EXTRACT(")); //Postgres function name
visitor.Visit(_params.First()); //First paramenter
visitor.Visit(new SqlFragmentExpression(" from ")); //query clause
visitor.Visit(_params.Skip(1).First()); //2nd parameter
visitor.Visit(new SqlFragmentExpression(")")); //function ending brace
return this;
}
protected override void Print([NotNullAttribute] ExpressionPrinter expressionPrinter)
{
Console.WriteLine(expressionPrinter);
}
}
Add below code in OnModeCreating
function
modelBuilder.HasDbFunction(ExtractMethod)
.HasTranslation(expressions =>
{
return new ExtractExpression(expressions);
});
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.