SQL Query 和 SqlClient 操作的区别

Difference between SQL Query and SqlClient operation

我正在尝试使用存储过程从 SQL Server 2008 R2 数据库中查询数据。代码执行无误,但查询未返回任何结果。当通过 SQL Server Management Studio 使用完全相同的参数调用相同的存储过程时,会正确返回数据。我不知道是什么原因导致的,可能是 SqlClient 实现的特定原因?查询returns两个DateTime2值之间的所有数据;如果我使这些 DateTime2 值相距足够远,则会返回数据。显然这不是期望的行为。

C# 代码(startTime.HasValueendTime.HasValue 在这种情况下为真):

if (conn.State == ConnectionState.Closed)
{
    conn.Open();
}

SqlCommand comm = conn.CreateCommand();
comm.CommandType = CommandType.StoredProcedure;
comm.CommandText = "GetAllPropertyValues";

comm.Parameters.Add("@dataTypeName", SqlDbType.NVarChar).Value = dataTypeName;
comm.Parameters.Add("@propertyName", SqlDbType.NVarChar).Value = propertyName;

if (startTime.HasValue)
{
    var startString = startTime.Value.ToUniversalTime().ToString("O");

    if (endTime.HasValue)
    {
        var endString = endTime.Value.ToUniversalTime().ToString("O");

        comm.CommandText += "Between";
        comm.Parameters.Add("@startTime", SqlDbType.DateTime2).Value = startString;
        comm.Parameters.Add("@endTime", SqlDbType.DateTime2).Value = endString;
    }
    else
    {
        comm.CommandText += "After";
        comm.Parameters.Add("@dateTime", SqlDbType.DateTime2).Value = startString;
    }
}

SqlDataReader reader = comm.ExecuteReader();

while (reader.Read())
{
    // ...
}

SQL 服务器存储过程:

declare @str varchar(max) = 'select * from [dbo].[' + @tableName + '] where StartTime BETWEEN ''' +
                                    CAST(@startTime as nvarchar(max)) + ''' AND ''' + CAST(@endTime as nvarchar(max)) + ''' order by StartTime asc'
exec(@str)

执行的示例查询:

USE [Construct3]
GO

DECLARE @return_value int

EXEC    @return_value = [dbo].[GetAllPropertyValuesBetween]
        @datatypeName = N'HeadPose',
        @propertyName = N'HeadRotationRadiansZ',
        @startTime = '2014-12-31T19:00:00.0000000Z',
        @endTime = '2014-12-31T20:00:00.0000000Z'

SELECT  'Return Value' = @return_value
GO

更改 CommandText 属性 会清除 Parameters 集合。完成文本后设置所有参数。

此外,您所拥有的将容易受到 sql 注入攻击。您应该使用 sp_executesql,而不是 exec(),以便您的时间参数得到安全处理。我会给你一个疑问,即 @tableName 参数不是用户可以输入任意文本的地方,而是必须从服务器验证的表列表中进行选择。

假设存储过程中的 @startTime@endTime 参数类型为 DATETIME 那么您要进行从日期时间到字符串的双重转换,首先是在您的 C# 代码:

var startString = startTime.Value.ToUniversalTime().ToString("O"); //This will create the datetime as a string using .NET format

您将它作为 DateTime2:

传递给存储过程

comm.Parameters.Add("@startTime", SqlDbType.DateTime2).Value = startString;

然后在 SQL 上将其转换回字符串格式:

CAST(@startTime as nvarchar(max))

这可能是问题所在,当您在 .NET 和 SQL 中进行从 DATETIME 到字符串的转换时,不要期望它们有相同的结果,所以当您执行存储数据库上的过程你得到了结果,但是当你从 .NET 调用它时,没有结果,因为日期是错误的。我建议做的是将这些日期参数的值作为普通 .NET DateTime 值传递,并在存储过程中将其转换为 varchar。您可以使用 SQL 中的 CONVERT 函数来实现这一点,查看 this link 了解有关 CONVERT 日期格式的更多信息。

希望这对您有所帮助。