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: