从我的C#应用程序中,我使用TVP
调用存储过程。几列是datetime
。对SP的调用可能类似于:
declare @p1 dbo.MyTvp
insert into @p1 values('2020-03-19 00:00:01','2020-03-30 23:59:59')
exec MySp @criteria=@p1
以上代码是用C#自动生成的。在SP中,处理日期的部分是:
declare @datefrom datetime;
---
SET @sql = CONCAT(@sql, ' AND date_from >= ''', @datefrom, '''');
SQL Server语言环境为德语。
由于从varchar到datetime的转换,以上引发错误。但是,如果我传递的日期时间值的格式如下:
declare @p1 dbo.MyTvp
insert into @p1 values('19.03.2020 00:00:01','30.03.2020 23:59:59')
exec MySp @criteria=@p1
SP正常工作。
用作源的类是:
public class MyCriteria
{
public DateTime DateFrom { get; set; }
}
表类型为:
CREATE TYPE [dbo].[MyTvp] AS TABLE(
[DateFrom] [datetime] NULL
)
我使用扩展方法将MyCriteria
的实例转换为DataTable
,然后使用Dapper执行SP:
var criteria = new List<MyCriteria>() { myCriteria }.ToDataTable();
return await conn.QueryAsync<SomeResult>(new CommandDefinition("MySp", new { criteria }, commandType: CommandType.StoredProcedure, cancellationToken: ct));
我不知道是在哪个阶段发生从datetime
到varchar
或DateTime
到string
的转换。
所以我到底需要转换日期才能使SP正常工作?我应该在数据库级别还是在C#应用程序中进行转换?
从评论中的讨论开始,听起来像是:输入TVP中的数据(datetime
),而b:在这种情况下,只有一行;太好了-这意味着我们可以大大简化;我们在这里要做的就是将TVP中的值引入本地,并与之一起使用。现在,基于示例代码中的@datefrom
,听起来您已经完成了第一步,因此我们所需要做的就是修复动态SQL的构成和执行方式。在问题中,我们有:
SET @sql = CONCAT(@sql, ' AND date_from >= ''', @datefrom, '''');
大概后面跟着:
EXEC (@sql);
相反,我们可以参数化动态SQL:
SET @sql = @sql + ' AND date_from >= @datefrom ';
并传递参数进入我们的动态SQL:
exec sp_executesql @sql, N'@datefrom datetime', @datefrom
sp_executesql
的第二个参数给出了所有actual参数的定义字符串,这些参数顺序在它之后。
现在,代码对于SQL注入是完全安全的,并且您无需担心任何字符串/日期转换。
请注意,在“内部”和“外部”部分中的参数名称不必相同,但是它们通常是相同的(为方便起见和可维护性)。