从字符串转换datetime时转换失败

时间:2010-06-09 17:36:30

标签: c# sql-server-2005 visual-studio-2008

我正在开发一个C#VS 2008 / SQL Server 2005 Express网站应用程序。我已经尝试了一些针对这个问题的修复,但是我的调用栈与其他问题不同。而这些修复并没有解决我的问题。我可以采取哪些措施来解决这个问题?

这是我的错误:

System.Data.SqlClient.SqlException was caught
  Message="Conversion failed when converting datetime from character string."
  Source=".Net SqlClient Data Provider"
  ErrorCode=-2146232060

  LineNumber=10
  Number=241
  Procedure="AppendDataCT"
  Server="\\\\.\\pipe\\772EF469-84F1-43\\tsql\\query"
  State=1
  StackTrace:
       at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
       at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
       at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj)
       at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
       at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
       at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async)
       at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result)
       at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(DbAsyncResult result, String methodName, Boolean sendToPipe)
       at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
       at ADONET_namespace.ADONET_methods.AppendDataCT(DataTable dt, Dictionary`2 dic) in c:\Documents and Settings\Admin\My Documents\Visual Studio 2008\WebSites\Jerry\App_Code\ADONET methods.cs:line 102

这是相关的代码。当我调试这段代码时,“dic”只循环遍历3列名,但没有查看存储在“dt”数据表中的行值。

public static string AppendDataCT(DataTable dt, Dictionary<string, string> dic)
{
    if (dic.Count != 3)
        throw new ArgumentOutOfRangeException("dic can only have 3 parameters");

    string connString = ConfigurationManager.ConnectionStrings["AW3_string"].ConnectionString;
    string errorMsg;

    try
    {               
        using (SqlConnection conn2 = new SqlConnection(connString))
        {
            using (SqlCommand cmd = conn2.CreateCommand())
            {
                cmd.CommandText = "dbo.AppendDataCT";
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.Connection = conn2;
                foreach (string s in dic.Keys)
                {
                    SqlParameter p = cmd.Parameters.AddWithValue(s, dic[s]);
                    p.SqlDbType = SqlDbType.VarChar;
                }

                conn2.Open();
                cmd.ExecuteNonQuery();
                conn2.Close();
                errorMsg = "The Person.ContactType table was successfully updated!";
            }
        }
    }

这是我的SQL存储过程:

ALTER PROCEDURE [dbo].[AppendDataCT] 
@col1 VARCHAR(50), 
@col2 VARCHAR(50),
@col3 VARCHAR(50)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @TEMP DATETIME
SET @TEMP = (SELECT CONVERT (DATETIME, @col3))

INSERT INTO Person.ContactType (Name, ModifiedDate)
VALUES( @col2, @TEMP)
END

输入文件有3列。前两个是varchars,但第三个也是我认为的varchar,但它表示为“3/11/2010”。在此输入文件中,示例行如下所示: “本杰明|早餐| 3/11/2010”。 我正在尝试将此日期字段从字符串转换为我的SP中的日期时间。我是以错误的方式去做的吗?

的DataRow: COL1 | COL2 | COL3 11 | A2 | 1978年1月10日 12 | B2 | 1978年2月10日 13 | C2 | 1978年3月10日 14 | D2 | 1978年4月10日

5 个答案:

答案 0 :(得分:5)

我认为Belousov Pavel是正确的。在foreach中,您将每个字典项目指定为参数。这些参数中的每一个都被定义为VarChar。通过提供的信息,可以合理地假设问题出在存储过程中。

您可以发布存储过程的代码,也可以尝试通过在那里执行存储过程来重新创建SQL Management Studio中的错误。

<强> UPDATE ...

查看存储过程后,代码看起来是正确的。我能够使用以下sql代码生成您正在获取的错误消息。

宣布@ col3 varchar(50)

设置@ col3 ='| 3/11/2010'

声明@temp datetime

设置@temp =(选择convert(datetime,@ col3))

请注意,@ col3的值以竖线字符开头。如果删除管道字符,它可以正常工作。

我会仔细查看字典中您从中获取参数值的值。解析数据的方式可能存在问题。

更新2

以下代码未确认可行,但我想我知道您要做的是什么。我假设你传入的DataTable有这样的数据:

COL1 | COL2 | COL3 11 | A2 | 1978年1月10日 12 | B2 | 1978年2月10日 13 | C2 | 1978年3月10日 14 | D2 | 1978年4月10日

如果是这种情况,我们不需要最初传入的字典。我还可以假设您希望对DataTable中的每一行执行一次存储过程。下面的方法类似于你在做什么,虽然它为每一行运行存储过程。

我不确定你的解释是,DataTable的第一行是否包含列的名称,如果不是没有后顾之忧。希望这是有道理的,如果您有疑问,请留下更多评论。

    public static string TestMethod(DataTable dt)
    {
        string connString = "";
        string errorMsg = string.Empty;

        try
        {
            //loop through each row of the datatable. Not sure if the column names is a row.
            foreach (DataRow row in dt.Rows)
            {
                using (SqlConnection conn2 = new SqlConnection(connString))
                {
                    using (SqlCommand cmd = conn2.CreateCommand())
                    {
                        cmd.CommandText = "dbo.AppendDataCT";
                        cmd.CommandType = CommandType.StoredProcedure;
                        cmd.Connection = conn2;

                        cmd.Parameters.Add(new SqlParameter() { ParameterName = "@col1", SqlDbType = SqlDbType.VarChar, Value = row[0] });
                        cmd.Parameters.Add(new SqlParameter() { ParameterName = "@col2", SqlDbType = SqlDbType.VarChar, Value = row[1] });
                        cmd.Parameters.Add(new SqlParameter() { ParameterName = "@col3", SqlDbType = SqlDbType.VarChar, Value = row[2] });

                        conn2.Open();
                        cmd.ExecuteNonQuery();
                        conn2.Close();
                    }
                }                
            }
            errorMsg = "The Person.ContactType table was successfully updated!";
        }
        catch
        {
        }

        return errorMsg;
    }

答案 1 :(得分:2)

好吧,如果你这样做:

SqlParameter p = cmd.Parameters.AddWithValue(s, dic[s]);
p.SqlDbType = SqlDbType.VarChar;

所有参数都是VARCHAR类型。这听起来可能很聪明 - 事实并非如此。

如果您将日期作为varchar传递,则开始涉及日期/时间字符串格式的混乱业务 - 除非您始终使用适用于任何SQL Server安装的ISO-8601格式YYYYMMDD,并且可以使用任何语言环境/语言/日期设置。其他任何事都变成了赌博。并非整个世界都使用美国的MM / DD / YYYY格式,并且根据您的SQL Server语言或日期格式设置,您的日期可能无法识别,甚至可能被误解。只是不要这样做 - 这是一团糟。

另外,真的 - 如果你在你的C#代码中有一个日期/时间 - 我强烈建议你把它作为SqlDbType.DateTime传递给你的SQL服务器存储过程。你只是要节省你自己无休止的调试时间和凌乱的转换时间和stuf .......

答案 2 :(得分:1)

我认为问题出在存储过程中。可能是DateTime之一的输入参数,但您将VarChar写入此参数。

更新

我可以看到你没有在方法DataTable dt中使用AppendDataCT

您写道,dic包含值[0]:[col1,col1] [1]:[col2,col2] [2]:[col3,col3]。但这是错误的价值......你的代码是

SqlParameter p = cmd.Parameters.AddWithValue(s, dic[s]);

然后你发送到col3 value = col3,据我所知。

可能是你想写的

SqlParameter p = cmd.Parameters.AddWithValue(s, dt[s]);

或类似的东西......

答案 3 :(得分:1)

你需要遍历DataTable的行来获取数据 - 你将dic的值(你的月,日,年的列名称)添加为SqlParameters .....这就是我的意思我假设因为这个问题非常分散......

注意:代码不完全正常 -

foreach(DataRow dr in dt.Rows)
{
    DateTime date = new DateTime();

    foreach(string s in dic.Keys)
    {  
        switch(dic[s])
        {
            case "Month":
                date.Month = dr[dic[s]];
                break;
            case "Day":
                date.Day = dr[dic[s]];
                break;
            case "Year":
                date.Year = dr[dic[s]];
                break;
        }

    }

    // If valid date
    SqlParameter p = cmd.Parameters.AddWithValue("Date", date);
    p.SqlDbType = SqlDbType.DateTime;      


}

更新:您需要处理自己的数据验证 - 否则,请转到

    using (SqlConnection conn2 = new SqlConnection(connString))
    {
        using (SqlCommand cmd = conn2.CreateCommand())
        {
            conn2.Open();               


            foreach(DataRow dr in dt.Rows)
            {
                 SqlParameter col1 = cmd.Parameters.AddWithValue(dic[0], dr[0].ToString());
                 SqlParameter col2 = cmd.Parameters.AddWithValue(dic[1], dr[1].ToString());
                 SqlParameter col3 = cmd.Parameters.AddWithValue(dic[2], Convert.ToDateTime(dr[2]));

                 cmd.ExecuteNonQuery();

            }

            conn2.Close();
        }
   }

答案 4 :(得分:0)

对于我来说,我的INSERT查询值的顺序错误:

INSERT INTO my_table(
     status       --varchar
    , created_on  --datetime2
) VALUES (
     @created_on  --datetime2
    , @status     --varchar
)