如何正确地将DateTime从C#传递给SQL?

时间:2017-07-19 14:39:32

标签: c# sql-server datetime

我正在尝试从C#运行存储过程,并且在单元测试时遇到转换错误。我见过的这个问题的每个搜索结果都表明使用ToString()不是传递DateTime的首选方法。

C#代码:

using (SqlConnection lvConn = new SqlConnection(gvSQLConnectionS))
{
    lvConn.Open();
    SqlCommand lvCmd = new SqlCommand(gvSQLsp, lvConn);
    lvCmd.CommandType = CommandType.StoredProcedure;
    lvCmd.Parameters.Add(new SqlParameter(gvSQLparamFunction, gvSQLfunctionUpdLE));
    lvCmd.Parameters.Add(new SqlParameter(gvSQLparamID, lvAAAID));
    lvCmd.Parameters.Add(new SqlParameter(gvSQLparamName, lvName));
    lvCmd.Parameters.Add(new SqlParameter(gvSQLparamPath, lvPath)); 
    SqlParameter lvParameterLE = lvCmd.Parameters.Add(gvSQLparamLE, SqlDbType.DateTime);
    SqlDateTime lvDTnow = new SqlDateTime(DateTime.Now);
    lvParameterLE.Value = lvDTnow;
    lvCmd.ExecuteNonQuery();
}

SQL安装程序: 上次执行(datetime,null)

存储过程:

ALTER PROCEDURE [dbo].[sp_BackupCleaner]
    @lvFunction int,
    @lvAAAID varchar(12) = NULL,
    @lvAAAID_new varchar(12) = NULL,
    @lvName varchar(35) = NULL,
    @lvName_new varchar(35) = NULL,
    @lvPath varchar(255) = NULL,
    @lvPath_new varchar(255) = NULL,
    @lvLastExecuted datetime = NULL
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @lvSQL varchar(max)    
IF @lvFunction = 6
    BEGIN
        SET @lvSQL = 'UPDATE [dbo].[Backup_Paths]
                SET [dbo].[Backup_Paths].[Last Executed] = '+@lvLastExecuted+'
                WHERE [dbo].[Backup_Paths].[AAA Client ID] = '''+@lvAAAID+'''
                AND [dbo].[Backup_Paths].[Process Name] = '''+@lvName+'''
                AND [dbo].[Backup_Paths].[UNC Path] = '''+@lvPath+''''
    END

execute(@lvSQL)
END

抛出异常:

System.Data.SqlClient.SqlException: Conversion failed when converting date and/or time from character string.

3 个答案:

答案 0 :(得分:3)

执行SET SHOWPLAN_XML OFF;时与在C#中使用SET [dbo].[Backup_Paths].[Last Executed] = '+@lvLastExecuted+'一样糟糕。

如果您没有进一步动态修改.ToString(),您可以直接执行查询

@lvSQL

如果您要进一步编辑查询,则需要使用sp_executesql并将参数转发到动态查询。

IF @lvFunction = 6
BEGIN
    UPDATE [dbo].[Backup_Paths]
            SET [dbo].[Backup_Paths].[Last Executed] = @lvLastExecuted
            WHERE [dbo].[Backup_Paths].[AAA Client ID] = @lvAAAID 
            AND [dbo].[Backup_Paths].[Process Name] =  @lvName
            AND [dbo].[Backup_Paths].[UNC Path] = @lvPath
END

答案 1 :(得分:1)

无需使用动态SQL。通常应避免使用动态SQL。很难找到动态SQL无法被更好的东西取代的情况。

只需编写并运行您想要的语句:

IF @lvFunction = 6
    BEGIN
        UPDATE [dbo].[Backup_Paths]
            SET [dbo].[Backup_Paths].[Last Executed] = @lvLastExecuted
            WHERE [dbo].[Backup_Paths].[AAA Client ID] = @lvAAAID
            AND [dbo].[Backup_Paths].[Process Name] = @lvName
            AND [dbo].[Backup_Paths].[UNC Path] = @lvPath
    END

注意

如果存储过程执行许多不同的任务,那么强烈的迹象表明它应该分解为单独的过程。

答案 2 :(得分:-1)

enter image description here问题是尝试使用+运算符将Datetime变量与字符串文字连接起来。如果您使用的是SqlServer 2012或更高版本,则可以使用CONCAT,这样可以解决问题。 (但是当该值为NULL时,可能会使查询失败)

CONCAT('select blah blah blah', @myDateTimeValue);