Cinq ans de retard à la fête.
Il est mentionné dans les liens fournis de la réponse acceptée, mais je pense qu'il mérite une réponse explicite sur SO - en construisant dynamiquement la requête en fonction des paramètres fournis. Par exemple:
Installer
-- drop table Person
create table Person
(
PersonId INT NOT NULL IDENTITY(1, 1) CONSTRAINT PK_Person PRIMARY KEY,
FirstName NVARCHAR(64) NOT NULL,
LastName NVARCHAR(64) NOT NULL,
Title NVARCHAR(64) NULL
)
GO
INSERT INTO Person (FirstName, LastName, Title)
VALUES ('Dick', 'Ormsby', 'Mr'), ('Serena', 'Kroeger', 'Ms'),
('Marina', 'Losoya', 'Mrs'), ('Shakita', 'Grate', 'Ms'),
('Bethann', 'Zellner', 'Ms'), ('Dexter', 'Shaw', 'Mr'),
('Zona', 'Halligan', 'Ms'), ('Fiona', 'Cassity', 'Ms'),
('Sherron', 'Janowski', 'Ms'), ('Melinda', 'Cormier', 'Ms')
GO
Procédure
ALTER PROCEDURE spDoSearch
@FirstName varchar(64) = null,
@LastName varchar(64) = null,
@Title varchar(64) = null,
@TopCount INT = 100
AS
BEGIN
DECLARE @SQL NVARCHAR(4000) = '
SELECT TOP ' + CAST(@TopCount AS VARCHAR) + ' *
FROM Person
WHERE 1 = 1'
PRINT @SQL
IF (@FirstName IS NOT NULL) SET @SQL = @SQL + ' AND FirstName = @FirstName'
IF (@LastName IS NOT NULL) SET @SQL = @SQL + ' AND FirstName = @LastName'
IF (@Title IS NOT NULL) SET @SQL = @SQL + ' AND Title = @Title'
EXEC sp_executesql @SQL, N'@TopCount INT, @FirstName varchar(25), @LastName varchar(25), @Title varchar(64)',
@TopCount, @FirstName, @LastName, @Title
END
GO
Usage
exec spDoSearch @TopCount = 3
exec spDoSearch @FirstName = 'Dick'
Avantages:
- facile à écrire et à comprendre
- flexibilité - générer facilement la requête pour des filtrages plus délicats (par exemple, TOP dynamique)
Les inconvénients:
- problèmes de performances possibles en fonction des paramètres fournis, des index et du volume de données
Pas de réponse directe, mais lié au problème, c'est-à-dire la vue d'ensemble
Habituellement, ces procédures stockées de filtrage ne flottent pas, mais sont appelées à partir d'une couche de service. Cela laisse la possibilité de déplacer la logique métier (filtrage) de SQL vers la couche de service.
Un exemple utilise LINQ2SQL pour générer la requête en fonction des filtres fournis:
public IList<SomeServiceModel> GetServiceModels(CustomFilter filters)
{
var query = DataAccess.SomeRepository.AllNoTracking;
// partial and insensitive search
if (!string.IsNullOrWhiteSpace(filters.SomeName))
query = query.Where(item => item.SomeName.IndexOf(filters.SomeName, StringComparison.OrdinalIgnoreCase) != -1);
// filter by multiple selection
if ((filters.CreatedByList?.Count ?? 0) > 0)
query = query.Where(item => filters.CreatedByList.Contains(item.CreatedById));
if (filters.EnabledOnly)
query = query.Where(item => item.IsEnabled);
var modelList = query.ToList();
var serviceModelList = MappingService.MapEx<SomeDataModel, SomeServiceModel>(modelList);
return serviceModelList;
}
Avantages:
- requête générée dynamiquement basée sur les filtres fournis. Aucun indicateur de reniflage de paramètre ou de recompilation nécessaire
- un peu plus facile à écrire pour ceux du monde OOP
- généralement optimisé pour les performances, car des requêtes "simples" seront émises (les index appropriés sont néanmoins nécessaires)
Les inconvénients:
- Les limitations LINQ2QL peuvent être atteintes et forcer une rétrogradation vers LINQ2Objects ou revenir à une solution SQL pure selon le cas
- une écriture imprudente de LINQ peut générer des requêtes terribles (ou de nombreuses requêtes, si les propriétés de navigation sont chargées)