晚了五年。
在提供的已接受答案的链接中提到了它,但我认为它应该得到一个明确的答案——根据提供的参数动态构建查询。例如:
设置
-- 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
程序
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
用法
exec spDoSearch @TopCount = 3
exec spDoSearch @FirstName = 'Dick'
优点:
- 易于书写和理解
- 灵活性 - 轻松生成更复杂过滤的查询(例如动态 TOP)
缺点:
不是直接回答,而是与问题相关,即大局
通常,这些过滤存储过程不会四处浮动,而是从某个服务层调用。这留下了将业务逻辑(过滤)从 SQL 转移到服务层的选项。
一个示例是使用 LINQ2SQL 根据提供的过滤器生成查询:
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;
}
优点:
- 基于提供的过滤器动态生成的查询。无需参数嗅探或重新编译提示
- 对 OOP 世界中的人来说更容易编写
- 通常性能友好,因为将发出“简单”查询(尽管仍然需要适当的索引)
缺点:
- 可能会达到 LINQ2QL 限制并根据情况强制降级到 LINQ2Objects 或返回纯 SQL 解决方案
- 粗心的 LINQ 编写可能会产生糟糕的查询(或许多查询,如果加载了导航属性)