Uma das várias novidades que surgiram no Entity Framework Core 2.0, foi o suporte para UDF: a utilização das funções pré-definas no banco de dados. Isso facilita muita coisa, a forma que o EFCore oferece esse recurso tornou mais fácil a utilização das funções existentes em nossos bancos de dados.
Nesse, te mostrarei como fazer a utilização desse recurso. Vale a pena ressaltar que essas funções serão traduzidas apenas no servidor, e não será avaliada do lado cliente (isso pode ser possível também, mas aqui irei apenas demonstrar como traduzir isso para o servidor).
A próxima versão EFCore 2.1 sairá com algumas funções para DATEDIFF já implementadas em EF.Functions.
Nosso primeiro exemplo será traduzir o DATEDIFF do SQL Server, o mesmo estará disponível na versão 2.1, porém, nosso intuito aqui é mostrar como traduzir funções usando o EF Core.
Primeiramente iremos criar uma classe para organizar nossas funções:
public class Funcoes
{
public static int SqlDateDiff(string tipo, DateTime inicio, DateTime fim)
=> 0;
public static string SqlLeft(object dados, int limite)
=> string.Empty;
public static string SqlReplace(object dados, string substituir, string por)
=> string.Empty;
}
Iremos criar nossas expressões no método OnModelCreating que serão traduzidas no servidor.
Primeira função (DATEDIFF):
builder
.HasDbFunction(typeof(Funcoes)
.GetMethod(nameof(Funcoes.SqlDateDiff)))
.HasTranslation(args =>
{
var argumentos = args.ToList();
argumentos[0] = new SqlFragmentExpression((string)((ConstantExpression)argumentos.First()).Value);
return new SqlFunctionExpression(
"DATEDIFF",
typeof(int),
argumentos);
});
Utilização da Função:
var teste01 = db
.Tests
.Where(p => Funcoes.SqlDateDiff("DAY", DateTime.Now, DateTime.Now) == 0)
.ToList();
Query Gerada no Servidor:
SELECT [p].[Id], [p].[Data], [p].[Nome] FROM [Tests] AS [p] WHERE DATEDIFF(DAY, GETDATE(), GETDATE()) = 0
Segunda função (LEFT):
builder
.HasDbFunction(typeof(Funcoes)
.GetMethod(nameof(Funcoes.SqlLeft)))
.HasTranslation(args =>
{
var argumentos = args.ToList();
return new SqlFunctionExpression(
"LEFT",
typeof(string),
argumentos);
});
Utilização da Função:
var teste02 = db
.Tests
.Select(p => new { TestLeft = Funcoes.SqlLeft(p.Nome, 20) })
.ToList();
Query Gerada no Servidor:
SELECT LEFT([p].[Nome], 20) AS [TestLeft] FROM [Tests] AS [p]
Terceira função (REPLACE):
builder
.HasDbFunction(typeof(Funcoes)
.GetMethod(nameof(Funcoes.SqlReplace)))
.HasTranslation(args =>
{
var argumentos = args.ToList();
return new SqlFunctionExpression(
"REPLACE",
typeof(string),
argumentos);
});
Utilização da Função:
var teste03 = db
.Tests
.Select(p => new { TestReplace = Funcoes.SqlReplace(p.Nome, "A", "B") })
.ToList();
Query Gerada no Servidor:
SELECT REPLACE([p].[Nome], N'A', N'B') AS [TestReplace] FROM [Tests] AS [p]
Todos os códigos utilizados em nossos exemplos estão reunidos aqui:
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Query.Expressions;
using System;
using System.Linq;
using System.Linq.Expressions;
namespace FunctionsEFCore2
{
class Program
{
static void Main(string[] args)
{
using (var db = new ExemploDb())
{
db.Database.EnsureCreated();
var teste01 = db
.Tests
.Where(p => Funcoes.SqlDateDiff("DAY", DateTime.Now, DateTime.Now) == 0)
.ToList();
var teste02 = db
.Tests
.Select(p => new { TestLeft = Funcoes.SqlLeft(p.Nome, 20) })
.ToList();
var teste03 = db
.Tests
.Select(p => new { TestReplace = Funcoes.SqlReplace(p.Nome, "A", "B") })
.ToList();
}
}
}
public class ExemploDb : DbContext
{
public DbSet<Test> Tests { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder builder)
{
builder.UseSqlServer("Server=.\\Sistemas,1433;Database=Teste_Functions;Integrated Security=True;");
}
protected override void OnModelCreating(ModelBuilder builder)
{
// Traduzir DATEDIFF
builder
.HasDbFunction(typeof(Funcoes)
.GetMethod(nameof(Funcoes.SqlDateDiff)))
.HasTranslation(args =>
{
var argumentos = args.ToList();
argumentos[0] = new SqlFragmentExpression((string)((ConstantExpression)argumentos.First()).Value);
return new SqlFunctionExpression(
"DATEDIFF",
typeof(int),
argumentos);
});
// Traduzir LEFT
builder
.HasDbFunction(typeof(Funcoes)
.GetMethod(nameof(Funcoes.SqlLeft)))
.HasTranslation(args =>
{
var argumentos = args.ToList();
return new SqlFunctionExpression(
"LEFT",
typeof(string),
argumentos);
});
// Traduzir REPLACE
builder
.HasDbFunction(typeof(Funcoes)
.GetMethod(nameof(Funcoes.SqlReplace)))
.HasTranslation(args =>
{
var argumentos = args.ToList();
return new SqlFunctionExpression(
"REPLACE",
typeof(string),
argumentos);
});
base.OnModelCreating(builder);
}
}
public class Funcoes
{
public static int SqlDateDiff(string tipo, DateTime inicio, DateTime fim)
=> 0;
public static string SqlLeft(object dados, int limite)
=> string.Empty;
public static string SqlReplace(object dados, string substituir, string por)
=> string.Empty;
}
public class Test
{
public int Id { get; set; }
public string Nome { get; set; }
public DateTime Data { get; set; }
}
}
Fico por aqui, e um forte abraço!
Fonte original em:



