2010-06-09 5 views
0

Je développe une application de site Web C# VS 2008/SQL Server 2005 Express. J'ai essayé quelques-uns des correctifs pour ce problème, mais ma pile d'appels diffère des autres. Et ces correctifs n'ont pas résolu mon problème. Quelles mesures puis-je prendre pour résoudre ce problème?La conversion a échoué lors de la conversion de datetime à partir d'une chaîne de caractères

Voici mon erreur:

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 

Et voici le code correspondant. Lorsque j'ai débogué ce code, "dic" a seulement bouclé les 3 noms de colonnes, mais n'a pas regardé dans les valeurs de ligne qui sont stockées dans "dt", la table de données.

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

Voici mon SQL stocké 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 

Le fichier d'entrée a 3 colonnes. Les deux premiers sont des varchars, mais le troisième est aussi varchar je pense, mais il est représenté par "3/11/2010". Dans ce fichier d'entrée, un exemple de ligne ressemble à: "Benjamin | breakfast | 3/11/2010". Et j'essaye de convertir ce champ de date d'une chaîne à un datetime ici dans mon SP. Est-ce que je vais dans le mauvais sens?

DataRow: col1 | col2 | col3 11 | A2 | 10.01.1978 12 | b2 | 10.02.1978 13 | c2 | 10.03.1978 14 | d2 | 10/04/1978

+4

Votre code me prêter à confusion. Pourquoi passez-vous dans un dictionnaire avec un nombre fixe d'éléments, puis en utilisant un type de paramètre 'VarChar' quand il attend un type datetime? –

+0

Quel type de données détenez-vous dans votre fichier dictionnaires et quelles sont les données dans le DataTable? J'ai une hypothèse, et une réponse, mais je dois m'en assurer. – TheGeekYouNeed

+0

Le dictionnaire dic contient les 3 en-têtes de colonne; DataTable contient les valeurs de ligne du fichier d'entrée. Jon, j'essaie de lire le champ date en tant que varchar. Voir le code mis à jour et les commentaires à la fin. – salvationishere

Répondre

4

Je pense que Belousov Pavel est correct. Dans votre foreach, vous affectez chaque élément du dictionnaire en tant que paramètre. Chacun de ces paramètres est défini comme étant VarChar. Avec les informations fournies, il est logique de supposer que le problème est dans la procédure stockée.

Pouvez-vous publier le code de la procédure stockée ou essayer de recréer l'erreur dans SQL Management Studio en y exécutant la procédure stockée.

MISE A JOUR ...

Après avoir regardé votre procédure stockée le code semble correct. J'ai été capable de générer le message d'erreur que vous obtenez en utilisant le code sql suivant.

@ col3 varchar déclare (50)

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

déclare @temp datetime

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

Notez que la valeur de @ col3 commence par un caractère de tuyau. Si vous supprimez le caractère de tuyau, cela fonctionne correctement.

Je regarderais de plus près les valeurs du dictionnaire pour lequel vous obtenez des valeurs de paramètres. Il peut y avoir un problème avec la façon dont vous avez analysé les données.

MISE À JOUR 2

Le code ci-dessous n'est pas confirmé au travail, mais je pense que je vois ce que vous essayez de faire. Je suppose que le DataTable vous passez en contient des données comme ceci:

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

Si tel est le cas, nous n'avons pas besoin du dictionnaire qui a été transmis à l'origine. Je peux également supposer que vous voulez que la procédure stockée soit exécutée une fois pour chaque ligne dans le DataTable. La méthode ci-dessous est similaire à ce que vous faites, bien qu'elle exécute la procédure stockée pour chaque ligne. Ce que je ne suis pas sûr de votre explication est si la première rangée du DataTable contient les noms des colonnes, sinon pas de soucis alors. J'espère que cela a du sens, laissez plus de commentaires si vous avez des 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; 
    } 
+0

Souhaitez-vous regarder mon code SP à la fin – salvationishere

+0

Merci Dev, mais comment puis-je faire cela dans le SP? Que suggérez-vous que je le change? – salvationishere

+0

Ne pensez pas que c'est un problème avec le SP maintenant. Veuillez déboguer le code C# et vérifier les valeurs dans l'objet dictionnaire (dic). Je parie que la valeur de la date a plus que la date et que cela provoque l'erreur de conversion. – DevDave

1

Le problème est dans la procédure stockée, je pense. Peut être l'un des paramètres d'entrée est DateTime, mais vous avez écrit VarChar à ce paramètre.

MISE À JOUR:

Comme je vous vois ne pas utiliser DataTable dt dans votre méthode AppendDataCT.

Vous avez écrit que dic contient des valeurs [0]: [col1, col1] [1]: [col2, col2] [2]: [col3, col3]. Mais il est faux de valeurs ... votre code est

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

Ensuite, vous envoyer à la valeur col3 = col3, que je comprends.

Peut être que vous vouliez écrire

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

ou quelque chose comme ça ...

+0

Voulez-vous s'il vous plaît regarder mon code SP? – salvationishere

+0

J'ai essayé ceci mais j'ai alors eu l'erreur: foreach (chaîne s dans dt) // dt.Keys) { SqlParameter p = cmd.Parameters.AddWithValue (s, dt); // [s]); p.SqlDbType = SqlDbType.VarChar; } l'instruction foreach ne peut pas fonctionner sur des variables de type 'System.Data.DataTable' car 'System.Data.DataTable' ne contient pas de définition publique pour 'GetEnumerator' – salvationishere

+0

Dans chaque cas, vous devez utiliser dic et AddWithValue - dt. –

2

Eh bien, si vous faites ceci:

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

tous vos paramètres sera de type VARCHAR. Cela peut paraître intelligent au début - ce n'est pas le cas. Si vous passez des dates en tant que varchar, vous commencez à entrer dans l'industrie des formats de chaînes date/heure - à moins que vous n'utilisiez toujours le format ISO-8601 YYYYMMDD qui fonctionne sur n'importe quelle installation SQL Server et avec n'importe quelle langue/réglage de la date. Tout le reste devient un pari. Le monde entier n'utilise pas le format MM/JJ/AAAA comme aux États-Unis et, en fonction des paramètres de langue ou de format de date de votre SQL Server, il se peut que votre date ne soit pas reconnue ou même mal interprétée. Ne fais pas ça, c'est un gâchis.

Plus, vraiment - si vous avez une date/heure dans votre code C# - Je fortement vous recommander passer que comme SqlDbType.DateTime à votre serveur SQL stockées proc. Vous allez juste vous épargner des heures interminables de débogage et de conversions en désordre .......

+0

Pouvez-vous regarder mon code SP à la fin? – salvationishere

+0

@Salvationishere: la conversion de ces échantillons en DATETIME fonctionne bien ** tant que votre serveur a défini "US English" comme langue. Je ne pense pas que ces trois échantillons causent le problème ... une autre entrée doit être désactivée en quelque sorte –

+0

Oui, l'anglais est défini comme langue – salvationishere

1

Vous devez parcourir les lignes du DataTable pour obtenir les données - vous ajoutez les valeurs de dic (vos noms de colonne pour le mois, le jour, l'année ??) comme SqlParameters ..... C'est ce que je suppose parce que la question est assez dispersée ....

Note: Ne fonctionne pas complètement le 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;  


} 

MISE À JOUR: Vous devrez gérer votre propre validation de données - sinon, ici vous allez

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(); 
     } 
    } 
+0

Merci, mais pourriez-vous s'il vous plaît consulter mon code SP? – salvationishere

Questions connexes