2010-06-22 2 views
0

J'utilise SqlDataAdapter.Update avec DataTables pour mettre à jour deux tables SQL dans une même transaction. Si l'insertion échoue, je veux annuler toutes les données. Ceci est mon code:TransactionScope ne recule pas avec SqlDataAdapter.Update

using (var conn = new SqlConnection(_connectionString)) 
{ 
    conn.Open(); 

    using (var scope = new TransactionScope()) 
    { 
     // Insert first table 
     using (var command = conn.CreateCommand()) 
     { 
      command.CommandText = 
       @"INSERT INTO TableA(Id, Data) 
        VALUES(@id, @data)"; 

      command.CommandType = CommandType.Text; 
      command.Parameters.Add(new SqlParameter("@id", SqlDbType.Int) { SourceColumn = "Id" }); 
      command.Parameters.Add(new SqlParameter("@data", SqlDbType.Char) { SourceColumn = "Data" }); 

      var adapter = new SqlDataAdapter(); 
      adapter.InsertCommand = command; 
      adapter.Update(tableADataTable); 
     } 

     // Insert second table 
     using (var command = conn.CreateCommand()) 
     { 
      command.CommandText = 
       @"INSERT INTO TableB(Id, Data) 
        VALUES(@id, @data)"; 

      command.CommandType = CommandType.Text; 
      command.Parameters.Add(new SqlParameter("@id", SqlDbType.Int) { SourceColumn = "Id" }); 
      command.Parameters.Add(new SqlParameter("@data", SqlDbType.Char) { SourceColumn = "Data" }); 

      var adapter = new SqlDataAdapter(); 
      adapter.InsertCommand = command; 
      adapter.Update(tableBDataTable); 
     } 

     scope.Complete(); 
    } 
} 

Le problème que je vais avoir est que si une exception est levée lors de la deuxième exécution de la commande, les données de la première commande est toujours commited. Ai-je besoin de reculer explicitement? Ou est comment TransactionScope devrait se comporter lors de l'utilisation de SqlDataAdapter.Update? Quelque chose à noter est qu'à l'origine j'avais la création de SqlConnection dans l'instruction using TransactionScope, mais je l'ai déplacée car je recevais des erreurs que mon serveur DB n'avait pas été configuré correctement pour les transactions distribuées. Le fait que ma création SqlConnection soit en dehors de TransactionScope est-il lié?

Répondre

1

Essayez de placer votre SqlConnection dans le TransactionScope, il devrait alors s'inscrire automatiquement dans la transaction.

Je pense que dans votre code, vous devez inscrire manuellement la connexion dans la transaction ... consultez les exemples dans ces liens.

http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnection.enlistdistributedtransaction(v=VS.71).aspx

http://msdn.microsoft.com/en-us/library/system.transactions.transactionscope.aspx

Désolé vient de prendre votre OP - peut-être il est parce que la connexion n'a pas été configuré pour engager automatiquement des opérations existantes (membre de la chaîne de connexion, je pense).

Si vous n'appelez pas Complete (ou Valider sur une transaction SqlTransaction), il sera automatiquement annulé.

Bien sûr, dans votre exemple de code actuel, vous pouvez utiliser en toute sécurité un objet SqlTransaction car vous n'avez pas besoin de plusieurs connexions/bases de données.

2

Je pense que vous devez déplacer votre appel conn.Open() à l'intérieur de la portée de transaction afin qu'il s'enrôle dans la transaction. En outre, assurez-vous que vous n'avez pas enslist=false; dans votre chaîne de connexion.

0

essayez d'insérer ce code

command.CommandText = @"SET autocommit = 0"; 
command.ExecuteNonQuery(); 

command.CommandText = @"SET sql_mode=TRADITIONAL"; 
command.ExecuteNonQuery(); 
Questions connexes