2012-04-28 1 views
80

Je souhaite exécuter plusieurs instructions d'insertion sur plusieurs tables. J'utilise dapper.net. Je ne vois aucun moyen de gérer les transactions avec dapper.net.transaction avec dapper dot net

Veuillez partager vos idées sur l'utilisation des transactions avec dapper.net.

Répondre

80

Voici l'extrait de code:

using System.Transactions;  
....  
using (var transactionScope = new TransactionScope()) 
{ 
    DoYourDapperWork(); 
    transactionScope.Complete(); 
} 

Notez que vous devez ajouter une référence à System.Transactions montage car il n'est pas référencé par défaut.

+2

Est-il nécessaire d'annuler explicitement une erreur ou est-ce que System.Transactions la gère automatiquement? –

+2

@NorbertNorbertson il le fait automatiquement, dans la méthode 'Dispose()'. Si 'Complete()' n'a pas été appelé, la transaction est annulée. –

15

Vous devriez pouvoir utiliser TransactionScope puisque Dapper exécute uniquement des commandes ADO.NET.

using (var scope = new TransactionScope()) 
{ 
    // insert 
    // insert 
    scope.Complete(); 
} 
70

Je préfère utiliser une approche plus intuitive en obtenant la transaction directement à partir de la connexion:

// This method will get a connection, and open it if it's not yet open. 
using (var connection = GetOpenConnection()) 
using (var transaction = connection.BeginTransaction()) 
{ 
    connection.Execute(
     "INSERT INTO data(Foo, Bar) values (@Foo, @Bar);", listOf5000Items, transaction); 
    transaction.Commit(); 
} 
+0

@ANeves: Eh bien, nous utilisons probablement différents frameworks Dapper, car celui-ci a: https://github.com/StackExchange/dapper-dot-net – andrecarlucci

+13

faut appeler connection.open() avant .begintransaction – Timeless

+0

Une connexion n'est pas automatiquement enrôlé dans transactionscope à moins que vous n'ouvriez la connexion au sein de la transactioncope. Je ne sais pas comment votre code fonctionne, si GetOpenConnection s'ouvre comme par magie dans le transactionscope, mais je parierais que ce n'est pas –

4

La réponse de Daniel a fonctionné comme prévu pour moi. Pour être complet, voici un extrait qui montre validation et d'annulation au moyen d'un champ de transaction et pimpant:

using System.Transactions; 
    // _sqlConnection has been opened elsewhere in preceeding code 
    using (var transactionScope = new TransactionScope()) 
    { 
     try 
     { 
      long result = _sqlConnection.ExecuteScalar<long>(sqlString, new {Param1 = 1, Param2 = "string"}); 

      transactionScope.Complete(); 
     } 
     catch (Exception exception) 
     { 
      // Logger initialized elsewhere in code 
      _logger.Error(exception, $"Error encountered whilst executing SQL: {sqlString}, Message: {exception.Message}") 

      // re-throw to let the caller know 
      throw; 
     } 
    } // This is where Dispose is called 
+2

@usr qui se résume à des préférences personnelles.Je préfère savoir la première fois que quelque chose s'est mal passé et que les consignes ne sont pas considérées comme des détritus. En outre, ma réponse annonce toujours la valeur en démontrant une façon d'utiliser des transactions avec dapper – dotnetguy

+0

@CodeNaked, d'abord, vous avez la commande mal là. Le bloc catch serait frappé en premier s'il y avait une exception, puis la fin de la portée d'utilisation. Deuxièmement, regardez cette réponse et le document MSDN référencé: http: //stackoverflow.com/a/5306896/190476 appelant disposer une seconde fois n'est pas dangereux, un objet bien conçu ignore le deuxième appel. La downvote n'est pas justifiée! – dotnetguy

+0

@dotnetguy - Je n'essayais pas de communiquer quelle méthode 'Dispose' est appelée première ou seconde, juste qu'elle est appelée deux fois. En ce qui concerne le fait que «l'appel de disposer une seconde fois n'est pas nuisible», c'est une grande hypothèse. J'ai appris que les documents et les implémentations ne sont souvent pas d'accord. Mais si vous voulez le mot de Microsoft pour cela: https://msdn.microsoft.com/en-us/library/ms182334.aspx?f=255&MSPPError=-2147217396 – CodeNaked

0

Compte tenu de toutes vos tables sont en base de données unique, je suis en désaccord avec TransactionScope solution proposée dans quelques réponses ici. Reportez-vous this réponse.

  1. TransactionScope est généralement utilisé pour les transactions distribuées; transaction couvrant différentes bases de données peut être sur un système différent. Cela nécessite certaines configurations sur le système d'exploitation et SQL Server sans lesquelles cela ne fonctionnera pas. Ceci n'est pas recommandé si toutes vos requêtes sont contre une seule instance de base de données.

  2. connection.BeginTransaction est la syntaxe ADO.NET pour implémenter la transaction (en C#, VB.NET, etc.) par rapport à une base de données unique. Cela ne fonctionne pas avec plusieurs bases de données.

Alors, connection.BeginTransaction() est la meilleure façon de faire.

Même la meilleure façon de gérer la transaction est de mettre en œuvre UnitOfWork comme expliqué dans la réponse this.

+0

Il n'est pas nécessaire d'avoir plusieurs bases de données pour bénéficier de TransactionScope. D'utilité particulière est que c'est ambiant. C'est génial pour emballer du code que vous ne possédez pas ou que vous ne pouvez pas modifier, dans une transaction. Par exemple, il peut être très utile lorsque le code de test d'unité/d'intégration effectue des appels de base de données sur lesquels vous souhaitez revenir après. Juste flotter un TransactionScope, tester le code, et disposer pendant le nettoyage de test. –

+0

@LarrySmith: D'accord; mais la question ne concerne pas cela. OP dit juste qu'il veut insérer dans plusieurs tables dans une transaction. Certaines réponses, y compris celle acceptée, suggèrent d'utiliser 'TransactionScope' qui est inefficace pour ce que OP veut. Je suis d'accord que 'TransactionScope' est un bon outil dans de nombreux cas; mais pas ça. –