Cinque anni di ritardo alla festa.
È menzionato nei collegamenti forniti della risposta accettata, ma penso che meriti una risposta esplicita su SO - costruendo dinamicamente la query in base ai parametri forniti. Per esempio:
Impostare
-- 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
Procedura
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
uso
exec spDoSearch @TopCount = 3
exec spDoSearch @FirstName = 'Dick'
Professionisti:
- facile da scrivere e capire
- flessibilità: genera facilmente la query per filtri più complicati (ad es. TOP dinamico)
Contro:
- possibili problemi di prestazioni a seconda dei parametri, degli indici e del volume di dati forniti
Risposta non diretta, ma relativa al problema noto anche come quadro generale
Di solito, queste procedure di filtraggio memorizzate non fluttuano, ma vengono chiamate da un livello di servizio. Ciò lascia l'opzione di spostare la logica aziendale (filtro) da SQL al livello di servizio.
Un esempio sta usando LINQ2SQL per generare la query in base ai filtri forniti:
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;
}
Professionisti:
- query generata dinamicamente in base ai filtri forniti. Non sono necessari suggerimenti di sniffing o ricompilazione dei parametri
- un po 'più facile da scrivere per quelli nel mondo OOP
- in genere ottimizzato per le prestazioni, poiché verranno inviate query "semplici" (sono comunque necessari indici appropriati)
Contro:
- Limitazioni di LINQ2QL possono essere raggiunte e forzare un downgrade a LINQ2Objects o tornare alla soluzione SQL pura a seconda del caso
- la scrittura incurante di LINQ potrebbe generare query terribili (o molte query, se le proprietà di navigazione sono caricate)