SQL Query和SqlClient操作之间的区别

时间:2015-01-06 00:14:09

标签: c# sql sql-server ssms sqlclient

我正在尝试使用存储过程从SQL Server 2008 R2数据库查询数据。代码执行时没有错误,但查询没有返回任何结果。当通过SQL Server Management Studio使用完全相同的参数调用此相同的存储过程时,将正确返回数据。我不知道是什么导致这种情况,可能是SqlClient实现的具体内容?查询返回两个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 Server存储过程:

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

2 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:1)

假设存储过程中的@startTime@endTime参数类型为DATETIME,那么您正在进行从datetime到string的双重转换,首先您要做的是它在你的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日期格式的更多信息。

希望这有帮助。