Crear una consulta SQL con una condición de filtrado dinámico es algo que tarde o temprano sale a la palestra
En la solución que se muestra a continuación, se usa un objeto de tipo ExpandoObject que permite agregar propiedades en tiempo de ejecución. Lo explica muy bien @eiximenis en el post Var, object y dynamic
Si a ExpandoObject le sumamos Dapper, la solución es segura contra SQL injection y flexible en cuanto a su confección
En el ejemplo he procurado que sea vea que podemos tanto agregar propierdades de forma dinámica por el mero hecho de asignar un valor, así como castear el ExpandoObject a un dicccionario para agregar propiedades de forma dinámica
Primero el código SQL para crear una tabla y que el ejemplo funcione
CREATE TABLE [dbo].[Table_1]( [Id] [int] NOT NULL, [TenantId] [int] NOT NULL, [C1] [int] NULL, [C2] [nvarchar](50) NULL, [C3] [datetime2](7) NULL, CONSTRAINT [PK_Table_1] PRIMARY KEY CLUSTERED ( [Id] ASC )
Ahora el código
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Dynamic;
using System.Linq;
using Dapper;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
QueryExample(new Dictionary<string, object>()
{
{ "C1", 1 },
{ "C2", "Foo" },
{ "C3", DateTime.Now }
});
}
private static void QueryExample(IDictionary<string, object> criterias)
{
const string connectionString = @"Server=(LocalDB)\MSSQLLocalDB;Database=Example;Trusted_Connection=True;";
var sql = "SELECT * FROM Table_1 WHERE TenantId = @TenantId";
var columnsWhitelist = new[] { "C1", "C2", "C3" };
foreach (var criteria in criterias)
{
if (!columnsWhitelist.Contains(criteria.Key))
{
throw new ArgumentException($"{criteria.Key} is not allowed as column name", nameof(criteria));
}
sql += $" AND {criteria.Key} = @{criteria.Key}";
}
dynamic parameters = new ExpandoObject();
parameters.TenantId = 1;
var dictionary = (IDictionary<string, object>)parameters;
foreach (var criteria in criterias)
{
dictionary.Add(criteria.Key, criteria.Value);
}
using (var connection = new SqlConnection(connectionString))
{
connection.Query(sql, (ExpandoObject)parameters);
}
Console.ReadKey();
}
}
}
El SQL que se ejecuta finalmente es el siguiente
exec sp_executesql N'SELECT * FROM Table_1 WHERE TenantId = @TenantId AND C1 = @C1 AND C2 = @C2 AND C3 = @C3',N'@TenantId int,@C1 int,@C2 nvarchar(4000),@C3 datetime',@TenantId=1,@C1=1,@C2=N'Foo',@C3='2018-01-31 18:58:56.823'
Un saludo!