パーティーに5年遅れ。
受け入れられた回答の提供されたリンクで言及されていますが、SOに関する明示的な回答に値すると思います-提供されたパラメーターに基づいてクエリを動的に構築します。例えば:
設定
-- 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 を不注意に記述すると、ひどいクエリ (ナビゲーション プロパティが読み込まれている場合は多くのクエリ) が生成される可能性があります。