Fünf Jahre zu spät zur Party.
Es wird in den bereitgestellten Links der akzeptierten Antwort erwähnt, aber ich denke, es verdient eine explizite Antwort auf SO - dynamisches Erstellen der Abfrage basierend auf den bereitgestellten Parametern. Z.B:
Konfiguration
-- 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
Verfahren
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
Verwendung
exec spDoSearch @TopCount = 3
exec spDoSearch @FirstName = 'Dick'
Vorteile:
- leicht zu schreiben und zu verstehen
- Flexibilität - Generieren Sie einfach die Abfrage für schwierigere Filter (z. B. dynamisches TOP).
Nachteile:
- Mögliche Leistungsprobleme in Abhängigkeit von den angegebenen Parametern, Indizes und dem Datenvolumen
Keine direkte Antwort, sondern im Zusammenhang mit dem Problem, auch bekannt als das große Ganze
Normalerweise schweben diese gespeicherten Filterprozeduren nicht herum, sondern werden von einer Service-Schicht aufgerufen. Dies lässt die Möglichkeit, die Geschäftslogik (Filterung) von SQL auf die Serviceschicht zu verlagern.
Ein Beispiel ist die Verwendung von LINQ2SQL, um die Abfrage basierend auf den bereitgestellten Filtern zu generieren:
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;
}
Vorteile:
- dynamisch generierte Abfrage basierend auf bereitgestellten Filtern. Es sind keine Parameter-Sniffing- oder Neukompilierungshinweise erforderlich
- etwas einfacher für diejenigen in der OOP-Welt zu schreiben
- In der Regel leistungsfreundlich, da "einfache" Abfragen ausgegeben werden (entsprechende Indizes werden jedoch weiterhin benötigt).
Nachteile:
- Je nach Fall können LINQ2QL-Einschränkungen erreicht werden, die ein Downgrade auf LINQ2Objects oder die Rückkehr zu einer reinen SQL-Lösung erzwingen
- Unachtsames Schreiben von LINQ kann zu schrecklichen Abfragen führen (oder zu vielen Abfragen, wenn Navigationseigenschaften geladen werden).