views:

492

answers:

4

I am developing a C# VS 2008 / SQL Server 2005 Express website application. I have tried some of the fixes for this problem but my call stack differs from others. And these fixes did not fix my problem. What steps can I take to troubleshoot this?

Here is my error:

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

And here is the related code. When I debugged this code, "dic" only looped through the 3 column names, but did not look into row values which are stored in "dt", the Data Table.

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!";
            }
        }
    }

Here is my SQL stored proc:

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

The input file has 3 columns. The first two are varchars, but the 3rd one is also varchar I think, but it's represented as "3/11/2010". In this input file, a sample row looks like: "Benjamin|breakfast|3/11/2010". And I am trying to convert this date field from a string to a datetime here in my SP. Am I going about it the wrong way?

DataRow: col1|col2|col3 11|A2|1/10/1978 12|b2|2/10/1978 13|c2|3/10/1978 14|d2|4/10/1978

+1  A: 

Problem is in stored procedure, I think. May be one of input parameters is DateTime, but you wrote VarChar to this parameter.

UPDATE:

As I can see you don't use DataTable dt in your method AppendDataCT.

You wrote that dic contains values [0]:[col1, col1] [1]:[col2, col2] [2]:[col3, col3]. But it's wrong values... your code is

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

Then you send to col3 value = col3, as I understand.

May be you wanted to write

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

or something like this...

Pavel Belousov
Would you please look at my SP code?
salvationishere
I tried this but then I got error: foreach (string s in dt) // dt.Keys) { SqlParameter p = cmd.Parameters.AddWithValue(s, dt); //[s]); p.SqlDbType = SqlDbType.VarChar; }foreach statement cannot operate on variables of type 'System.Data.DataTable' because 'System.Data.DataTable' does not contain a public definition for 'GetEnumerator'
salvationishere
In for each you should use dic, and in AddWithValue - dt.
Pavel Belousov
+3  A: 

I think Belousov Pavel is correct. Inside your foreach you assign each dictionary item as a parameter. Each of those parameters are defined as being VarChar. With the information provided it is logical to assume the problem is in the stored procedure.

Can you either post the code of the stored procedure or try and recreate the error inside SQL Management Studio by executing the stored procedure there.

UPDATE...

After looking at your stored procedure the code looks correct. I was able to generate the error message you are getting using the following sql code.

declare @col3 varchar(50)

set @col3 = '|3/11/2010'

declare @temp datetime

set @temp = (select convert(datetime,@col3))

Note that the value of @col3 starts with a pipe character. If you remove the pipe character it works correctly.

I would look closer at the values in the dictionary you are getting you parameter values from. There may be an issue with the way you parsed the data.

UPDATE 2

The code below is not confirmed to work but I think I see what you are trying to do. I assume the DataTable you are passing in has data like this:

col1|col2|col3 11|A2|1/10/1978 12|b2|2/10/1978 13|c2|3/10/1978 14|d2|4/10/1978

If this is the case we don't need the dictionary that was passed in originally. I can also assume that you want the stored procedure to be executed once for each row in the DataTable. The below method is similar to what you where doing although it runs the stored procedure for each row.

What I am not sure from you explanation is if the first row of the DataTable contains the names of the columns, if not no worries then. Hope this makes sense, leave more comments if you have questions.

    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;
    }
DevDave
Would you look at my SP code at the end
salvationishere
Thanks Dev, but how do I do this in the SP? What are you suggesting I change it to?
salvationishere
Don't think its an issue with the SP now. Please debug the C# code and check the values in the dictionary object (dic). I bet the value for the date has more then just the date and that is causing the conversion error.
DevDave
Yes, the "dic" values are correct:[0]:[col1, col1] [1]:[col2, col2] [2]:[col3, col3] But "dt" contains:[0]:12[1]:b2[2]:2/10/1978
salvationishere
I rechecked the sql and it is correct as long as a valid text date is entered as the value of @col3. So in the C# in debug mode just before executing the cmd.ExeceuteNotQuery() line, check the value of the third paramter and make sure there is no extra text included with the date value.BTW thanks for you patience...
DevDave
Sorry, could you explain me what does it means "[0]:[col1, col1]..." Is it key and value of dictionary?
Pavel Belousov
This means that index 0 has key="col1" and value="col1"
salvationishere
right now it is looping thru the keys, but this should loop through the values ("dt") instead--how would I do this?
salvationishere
My answer shows you how to loop through the DataTable.... look at the first line of the sample code I posted...
TheGeekYouNeed
Super! Your code worked for me, DevDave! Thank you so much!
salvationishere
+2  A: 

Well, if you do this:

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

all your parameters will be of type VARCHAR. This might sound smart at first - it's not.

If you pass dates as varchar, you start getting into the messy business of date/time string formats - unless you always use the ISO-8601 format YYYYMMDD which works on any SQL Server installation, and with any locale / language / date setting. Anything else becomes a gamble. Not the whole world uses the MM/DD/YYYY format as in the US, and depending on your SQL Server's language or date format settings, your date might not be recognized, or even misinterpreted. Just don't do it - it's a mess.

Plus, really - if you have a date/time in your C# code - I would strongly recommend you pass that as a SqlDbType.DateTime to your SQL Server stored proc. You're just gonna save yourself endless hours of debugging and messy conversions and stuf.......

marc_s
Can you look at my SP code at the end?
salvationishere
@Salvationishere: converting those samples into a DATETIME works okay **as long** as your server has "US English" set as its language. I don't think these three samples cause the trouble... some other entry must be off somehow
marc_s
Yes, English is set as its language
salvationishere
+1  A: 

You need to loop through the rows of the DataTable to get the data - you're adding the values of dic (your column names for month, day, year??) as SqlParameters..... This is what I'm assuming because the question is pretty scattered....

Note: Not completely functioning code -

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;      


}

UPDATE: You will need to handle your own data validation - otherwise, here you go

    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();
        }
   }
TheGeekYouNeed
Thanks, but would you please review my SP code?
salvationishere