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!