2012-07-28 4 views
0

Je ne suis pas compris tout code ici parce que je l'ai réécrite tant de fois au cours des derniers jours son vraiment pas la peine de continuer plus, je Je vais expliquer mon problème en termes génériques.exécution de plusieurs instructions/sqlcomands dans une seule transaction ado.net

J'ai une application WinForms écrite en C# et connecté à une base de données SQL Server. Dans certaines parties de mon application, je peux avoir jusqu'à 10 commandes SQL fonctionnant sur de nombreuses tables dans la base de données, et que je dois contenir dans une seule transaction, parce que c'est une situation de «tout ou rien». Si l'une des 10 commandes échoue, je souhaite qu'aucune des commandes ne soit validée.

facteurs aggravants comprennent:

  1. Chacun des 10 sqlcommands ont plusieurs paramètres
  2. Certains des sqlcommands utilisent INSERT et je dois utiliser le serveur identité généré dans certains des sqlcommands suivantes.
  3. Certaines commandes fonctionnent sur les mêmes données à savoir une commande précoce peut insérer un nouvel élément dans la base de données et l'un des sqlcommands plus tard tentera de mettre à jour cette même entrée.

Toute aide serait très appréciée car je suis à bout de nerfs avec ce problème ayant passé la majeure partie de la semaine là-dessus et ayant l'impression que relativement peu de progrès ont été réalisés.

EDIT:

Les sqlcommands étaient à l'origine dans les différentes classes, etc., mais je pensais que peut-être le problème donc je l'ai fait une grande ré-écriture et maintenant TOUS les sqlcommands sont dans la même méthode, bien que certains d'entre Les commandes sql sont écrites ailleurs et renvoyées à la méthode principale. Le problème pour le moment est que la première commande (INSERT) est exécutée, mais la transaction échoue à la deuxième commande car celle-ci tente de se référer à l'entrée de la base de données créée dans la première commande.

Je ne peux pas utiliser TransactionScope parce MSDTC sur le réseau provoque d'autres problèmes et donc je dois gérer cela avec mon application et ADO.NET.

EDIT (CERTAINS CODE)

Voici seulement les deux premiers sqlcommands dans la transaction:

string connectionString = aSystem.ConnectionString; 

    using (SqlConnection linkToDB = new SqlConnection(connectionString)) 
    { 
     linkToDB.Open(); 
     using (SqlTransaction transaction = linkToDB.BeginTransaction()) 
     { 
      try 
      {        
       //...Case...// 

       cCase c = new cCase(); 
       c.CaseType = cboCaseType.Text; 
       c.Occupation = txtOccupation.Text; 
       c.DateInstructed = txtDateInst.Text; 
       c.Status = "Live"; 
       SqlCommand sqlSaveCase = c.SaveSqlCom();        
       sqlSaveCase.Connection = linkToDB; 
       sqlSaveCase.Transaction = transaction; 
       c.SetCaseNo = sqlSaveCase.ExecuteNonQuery().ToString(); 

       //...IP Link...// 

       string strIPID = cboIPAddress.SelectedValue.ToString(); 
       SqlCommand sqlNewIPLink = cIPID.NewIPLinkSqlCom(strIPID,c.CaseNo,txtIPRef.Text); 
       sqlNewIPLink.Connection = linkToDB; 
       sqlNewIPLink.Transaction = transaction; 
       sqlNewIPLink.ExecuteNonQuery();    //...fails here...// 


       //...an additional 8 sql commands follow...// 

NUMÉRO

La commande sqlSaveCase PLAQUETTES un nouveau cas sur tblCases, mais quand la deuxième La commande sqlNewIPLink tente d'utiliser l'identité créée par le premier, elle génère une erreur de clé étrangère comme si elle ne voyait pas la casse nouvellement créée depuis la première commande.

+0

Les 10 commandes se trouvent-elles dans différents endroits du code. c'est-à-dire différentes classes, instances, etc. – devundef

+0

En quoi exactement avez-vous des problèmes? – Andreas

+0

On ne sait vraiment pas exactement quels sont vos problèmes. Pourquoi vous ne pouvez pas utiliser 'SqlTransaction'? Peut-être essayer de diviser ceci en plus de questions avec chacun traitant un problème * spécifique * qui peut être facilement démontré par un échantillon de code * simple *. –

Répondre

2

L'erreur était cette ligne

c.SetCaseNo = sqlSaveCase.ExecuteNonQuery().ToString(); 

qui devrait être en utilisant ExecutreScalar() afin de récupérer l'ID de la commande INSERT. L'indice est venu quand j'ai finalement réalisé qu'il revenait toujours 1, ce que je suppose est probablement juste un «vrai» booléen pour dire que la commande a été exécutée. Une fois que j'ai utilisé l'ExecuteScalar sur la commande à la place, il a commencé à renvoyer des ID plus significatifs que les SqlCommands suivants ont reconnu et par conséquent aucun problème de clé Foregin.

0

Vous pouvez utiliser TransactionScope Class pour cela.

here est la bonne explication.

espérons que cela aide.

+0

Ne peut pas utiliser MSDTC sur le réseau – PJW

0

dans votre cas, il est une bonne pratique d'utiliser modèle de commande. En fait, cela vous permet d'annuler vos opérations. La transaction est bonne pour quelques opérations. Mais avec 10 opérations, il vaut mieux exécuter chaque commande sur une boucle et si une commande échoue, annuler la commande.Cela implique que vous implémentiez l'opération de restauration (ici 10). ici un lien avec l'échantillon de motif: http: //www.dofactory.com/Patterns/PatternCommand.aspx

1

Pas sûr si cela est le problème, mais je ne vois pas où vous vous en utilisant c.SetCaseNo sur la deuxième SqlCommand.

// 
    // here you are setting c.SetCaseNo 
    // 
    c.SetCaseNo = sqlSaveCase.ExecuteNonQuery().ToString(); 

    string strIPID = cboIPAddress.SelectedValue.ToString(); 

    // 
    // but here you're using c.CaseNo 
    // 
    SqlCommand sqlNewIPLink = cIPID.NewIPLinkSqlCom(strIPID,c.CaseNo,txtIPRef.Text); 


    sqlNewIPLink.Connection = linkToDB; 
    sqlNewIPLink.Transaction = transaction; 
    sqlNewIPLink.ExecuteNonQuery(); 
+0

Merci pour cela - juste posté la réponse qui était le ExecuteNonQuery au lieu de ExecuteScalar. Le SetNewCase était juste un deuxième modificateur d'accès pour CaseNo qui contourne la validation intégrée dans ma classe. – PJW

Questions connexes