2013-06-17 7 views
0

Je sélectionne environ 20 000 enregistrements de la base de données, puis je les mets à jour un par un.
J'ai cherché cette erreur et j'ai vu que le réglage de CommandTimeout aidera, mais pas dans mon cas.
C# Erreur irrécupérable détectée lors de la lecture des données

 public void Initialize() 
    { 
     MySqlConnectionStringBuilder SQLConnect = new MySqlConnectionStringBuilder(); 
     SQLConnect.Server = SQLServer; 
     SQLConnect.UserID = SQLUser; 
     SQLConnect.Password = SQLPassword; 
     SQLConnect.Database = SQLDatabase; 
     SQLConnect.Port = SQLPort; 
     SQLConnection = new MySqlConnection(SQLConnect.ToString()); 
    } 

     public MySqlDataReader SQL_Query(string query) 
    { 
     MySqlCommand sql_command; 
     sql_command = SQLConnection.CreateCommand(); 
     sql_command.CommandTimeout = int.MaxValue; 
     sql_command.CommandText = query; 
     MySqlDataReader query_result = sql_command.ExecuteReader(); 
     return query_result; 
    } 

     public void SQL_NonQuery(string query) 
    { 
     MySqlCommand sql_command; 
     sql_command = SQLConnection.CreateCommand(); 
     sql_command.CommandTimeout = int.MaxValue; 
     sql_command.CommandText = query; 
     sql_command.ExecuteNonQuery(); 
    } 

Et voici ma méthode qui fait la requête de sélection:

 public void CleanRecords() 
    { 
     SQLActions.Initialize(); 
     SQLActions.SQL_Open(); 
     MySqlDataReader cashData = SQLActions.SQL_Query("SELECT `cash`.`id`, SUM(`cash`.`income_money`) AS `income_money`, `cash_data`.`total` FROM `cash_data` JOIN `cash` ON `cash`.`cash_data_id` = `cash_data`.`id` WHERE `user`='0' AND `cash_data`.`paymentterm_id`='0' OR `cash_data`.`paymentterm_id`='1' GROUP BY `cash_data_id`"); 
     while(cashData.Read()){ 
      if(cashData["income_money"].ToString() == cashData["total"].ToString()){ 
       UpdateRecords(cashData["id"].ToString()); 
      } 
     } 
     SQLActions.SQL_Close(); 
    } 

Et est la méthode ici qui fait la mise à jour:

 public void UpdateRecords(string rowID) 
    { 
     SQLActions.Initialize(); 
     SQLActions.SQL_Open(); 
     SQLActions.SQL_NonQuery("UPDATE `cash_data` SET `end_date`='" + GetMeDate() + "', `user`='1' WHERE `id`='" + rowID + "'"); 
     SQLActions.SQL_Close(); 
    } 

Modification de la structure de base de données n'est pas une option pour moi.
Je pensais que régler le timeout à la valeur max de int va résoudre mon problème, mais il semble que cela ne fonctionnera pas dans mon cas. Des idées? :)

EDIT: L'erreur que je reçois est "Erreur irrécupérable détectée lors de la lecture des données".





MISE À JOUR:

 public void CleanRecords() 
    { 
     StringBuilder dataForUpdate = new StringBuilder(); 
     string delimiter = ""; 

     SQLActions.Initialize(); 
     SQLActions.SQL_Open(); 
     MySqlDataReader cashData = SQLActions.SQL_Query("SELECT `cash`.`id`, SUM(`cash`.`income_money`) AS `income_money`, `cash_data`.`total` FROM `cash_data` JOIN `cash` ON `cash`.`cash_data_id` = `cash_data`.`id` WHERE `user`='0' AND `cash_data`.`paymentterm_id`='0' OR `cash_data`.`paymentterm_id`='1' GROUP BY `cash_data_id`"); 
     while (cashData.Read()) 
     { 
      if (cashData["income_money"].ToString() == cashData["total"].ToString()) 
      { 
       dataForUpdate.Append(delimiter); 
       dataForUpdate.Append("'" + cashData["id"].ToString() + "'"); 
       delimiter = ","; 
      } 
     } 
     SQLActions.SQL_Close(); 
     UpdateRecords(dataForUpdate.ToString()); 
    } 

    public void UpdateRecords(string rowID) 
    { 
     SQLActions.Initialize(); 
     SQLActions.SQL_Open(); 
     SQLActions.SQL_NonQuery("UPDATE `cash_data` SET `end_date`='" + GetMeDate() + "', `user`='1' WHERE `id` IN (" + rowID + ")"); 
     SQLActions.SQL_Close(); 
    } 
+1

Quelle est donc cette « erreur fatale »? – CodeCaster

+0

Quelle erreur renvoie? – Evans

+0

Est-il possible de nous donner les erreurs, le cas échéant? –

Répondre

1

Vous pourrez peut-être utiliser

UPDATE cash_data .... WHERE id IN (SELECT ....) 

et tout faire un aller. Sinon, vous pouvez le faire en deux étapes: d'abord le select recueille tous les identifiants, fermez la connexion, puis faites la mise à jour en obne avec tous les identifiants. Le code pour la deuxième option pourrait ressembler à ceci:

public void CleanRecords() 
    { 
     StringBuilder builder = new StringBuilder(); 
     string delimiter = ""; 

     SQLActions.Initialize(); 
     SQLActions.SQL_Open(); 
     MySqlDataReader cashData = SQLActions.SQL_Query("SELECT `cash`.`id`, SUM(`cash`.`income_money`) AS `income_money`, `cash_data`.`total` FROM `cash_data` JOIN `cash` ON `cash`.`cash_data_id` = `cash_data`.`id` WHERE `user`='0' AND `cash_data`.`paymentterm_id`='0' OR `cash_data`.`paymentterm_id`='1' GROUP BY `cash_data_id`"); 
     while(cashData.Read()){ 
      if(cashData["income_money"].ToString() == cashData["total"].ToString()){ 
       builder.Append(delimiter); 
       builder.Append("'" + cashData["id"].ToString() + "'"); 
       delimiter = ",";  
      } 
     } 
     SQLActions.SQL_Close(); 

     UpdateRecords(builder.ToString()); 


    } 

public void UpdateRecords(string rowIDs) 
{ 
    SQLActions.Initialize(); 
    SQLActions.SQL_Open(); 
    SQLActions.SQL_NonQuery("UPDATE `cash_data` SET `end_date`='" + GetMeDate() + "', `user`='1' WHERE `id` IN (" + rowIDs + ")"; 
    SQLActions.SQL_Close(); 
} 
+0

+1 juste pour l'utilisation intelligente du délimiteur, cependant, c'est la bonne direction à suivre, sauf pour les concaténations de chaînes, mais c'est un autre problème – Steve

+0

@Steve ehm ... la technique StringBuilder provient d'un extrait de code que j'ai copié de quelque part, donc (bien que je ne sache plus à qui l'attribuer) je ne vais pas m'en attribuer le mérite. EDIT: l'a trouvé, il était Jon Skeet, qui aurait pensé ... :) http://stackoverflow.com/questions/581448/join-a-string-using-delimiters –

+0

Excellent! Je vous remercie! Sauf que le stringbuilder je suppose insère une double citation (") dans la chaîne au début et à la fin, ce que mysql ne comprend pas correctement et il ne regarde pas dans la chaîne.Comment je peux me débarrasser d'eux? –

0

Il y a problèmes multiples:

Première: Vous avez lu les informations autour de 20K en utilisant un lecteur de données et de faire ensuite mettre à jour un par un dans le lecteur lui-même. Le lecteur maintient la connexion ouverte jusqu'à ce que vous avez terminé. Donc, ce n'est pas la bonne façon de le faire. Solution: Nous pouvons lire l'information en utilisant l'adaptateur de données. Deuxièmement: Plutôt que de faire une mise à jour un par un, nous pouvons mettre à jour en vrac en une seule fois. Il existe plusieurs options pour l'opération en bloc. Dans SQL u peut le faire soit par l'envoi d'informations au format XML ou u peut utiliser une table Valued Paramètre (PVT) (http://www.codeproject.com/Articles/22205/ADO-NET-and-OPENXML-to-Perform-Bulk-Database-Opera) OR (http://dev.mysql.com/doc/refman/5.5/en/load-xml.html)

+0

L'adaptateur de données est-il meilleur que le lecteur de données? –

+0

cela dépend au cas par cas. S'il vous plaît lire le lien ci-dessous http://stackoverflow.com/questions/1676753/sqldataadapter-vs-sqldatareader –

Questions connexes