Traduzindo funções para o servidor com EntityFramework Core
https://i0.wp.com/ralmsdeveloper172900781.files.wordpress.com/2017/12/efcore.png
Traduzindo funções no EntityFramework Core
Olá tudo bem?!
Uma de várias novidades que surgiu no EntityFramework Core 2.0 foi o suporte para UDF, a utilização das funções predefinas 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 pequeno artigo irei mostrar para você 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, mais isso pode ser possível também, mais aqui irei apenas demonstrar como traduzir isso para o servidor.
Na 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;
}
No método OnModelCreating é onde iremos criar nossas expressões 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]
**Todo código utilizado em nossos exemplos estão 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, abraços!