申し訳ありませんが、関数ピリオドで動的 SQL を実行することはできません。動的 SQL を必要としないように関数を書き直すことはできますが、それによって根本的な問題は本当に解決されるのでしょうか? プロシージャが必要であり、戻り値の型に関するこのまったく無関係な Entity Framework の問題によってまだ手錠をかけられている場合、あなたはどうしますか? 明らかに、EF を構成したり、プロシージャを接続したりする方法で何かが壊れています。そうしないと、結果セットを返すプロシージャで EF が機能しないと多くの人が不満を言うでしょう。その可能性は高いと思いますか?
CREATE FUNCTION dbo.GetLogApiCalls -- dbo prefix, always
(
@displayStart INT,
@displayLength INT, -- is this a page size, like 20, or @displayEnd?
@searchString NVARCHAR(1000),
@orderBy NVARCHAR(100),
@orderByDirection VARCHAR(4)
)
RETURNS TABLE
AS -- make it an inline TVF. Multi-statement TVFs can be a perf nightmare.
RETURN
(
SELECT * FROM
(
SELECT rn = ROW_NUMBER() OVER (ORDER BY
CASE @orderByDirection WHEN 'ASC' THEN
CASE @orderBy WHEN N'Provider' THEN Provider
WHEN N'RequestData' THEN RequestData
WHEN N'ResponseData' THEN ResponseData
WHEN N'UserName' THEN UserName
WHEN N'AccountName' THEN AccountName
WHEN N'MethodName' THEN MethodName
WHEN N'RequestIdentifier'
THEN CONVERT(CHAR(36), RequestIdentifier)
WHEN N'CreatedDate' THEN CONVERT(CHAR(23), CreatedDate, 126)
END
END,
CASE @orderByDirection WHEN 'ASC' THEN
CASE @orderBy WHEN N'Id' THEN Id
WHEN N'AccountId' THEN AccountId
WHEN N'CreatedUserId' THEN CreatedUserId
END
END,
CASE @orderByDirection WHEN 'DESC' THEN
CASE @orderBy WHEN N'Provider' THEN Provider
WHEN N'RequestData' THEN RequestData
WHEN N'ResponseData' THEN ResponseData
WHEN N'UserName' THEN UserName
WHEN N'AccountName' THEN AccountName
WHEN N'MethodName' THEN MethodName
WHEN N'RequestIdentifier'
THEN CONVERT(CHAR(36), RequestIdentifier)
WHEN N'CreatedDate' THEN CONVERT(CHAR(23), CreatedDate, 126)
END
END DESC,
CASE @orderByDirection WHEN 'DESC' THEN
CASE @orderBy WHEN N'Id' THEN Id
WHEN N'AccountId' THEN AccountId
WHEN N'CreatedUserId' THEN CreatedUserId
END
END DESC), [Id],[Provider],[RequestIdentifier],[RequestData],
[ResponseData],[UserName],[AccountName],[AccountId],
[CreatedUserId],[CreatedDate],[MethodName]
FROM dbo.LogAPICall
WHERE LEN(@searchString) = 0 OR
(
@searchString > '' AND
(
Provider LIKE '%' + @searchString + '%'
OR MethodName LIKE '%' + @searchString + '%'
)
)
) AS x
WHERE rn BETWEEN @displayStart AND @displayStart + @displayLength - 1 -- assumption
);
ただし、このダイナミクスORDER BY
は悪魔です。インライン TVF であっても、これは、ヒットを取得してOPTION (RECOMPILE)
参照クエリを追加することによって、さまざまなパラメーターに対してのみ適切に機能します。解決?動的 SQL でストアド プロシージャを使用し、Entity Framework 構成の問題を個別に把握します。ストアド プロシージャとして、これは次のようにはるかに優れています。
CREATE PROCEDURE dbo.GetLogApiCalls -- dbo prefix, always
@displayStart INT,
@displayLength INT, -- is this a page size, like 20, or @displayEnd?
@searchString NVARCHAR(1000),
@orderBy NVARCHAR(100),
@orderByDirection VARCHAR(4)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @sql NVARCHAR(MAX) = N'SELECT * FROM (
SELECT rn = ROW_NUMBER() OVER (ORDER BY '
+ @orderBy + ' ' + @orderByDirection + '),
[Id],[Provider],[RequestIdentifier],[RequestData],
[ResponseData],[UserName],[AccountName],[AccountId],
[CreatedUserId],[CreatedDate],[MethodName]
FROM dbo.LogAPICall'
+ CASE WHEN LEN(@searchString) > 0 THEN
' WHERE Provider LIKE ''%'' + @searchString + ''%''
OR MethodName LIKE ''%'' + @searchString + ''%'''
ELSE '' END
+ ') AS x
WHERE rn BETWEEN @displayStart
AND @displayStart + @displayLength - 1;';
DECLARE @params NVARCHAR(MAX) = N'@searchString NVARCHAR(1000),'
+ '@displayStart INT, @displayLength INT';
EXEC sp_executesql @sql, @params, @searchString, @displayStart, @displayLength;
END
GO
optimize for ad hoc workloads
特に設定を有効にしている場合。現在、これはパラメーター化できない動的な ORDER BY が原因で SQL インジェクションが発生しやすいため、これらのパラメーターに有効な値のみが含まれていることを検証する必要がある場合があります。