2010-03-23 3 views
9

J'ai le code suivant qui est dans une transaction. Je ne suis pas sûr où/quand je devrais commettre mon unité de travail. À cette fin, je n'ai pas mentionné quel type de Respoistory j'utilise - par exemple. Linq-To-Sql, Entity Framework 4, NHibernate, etc.À quelle ligne du code suivant devrais-je engager mon unité de travail?

Si quelqu'un sait où, peut-il s'il vous plaît expliquer pourquoi ils ont dit, où? (J'essaye de comprendre le modèle par l'exemple (s), par opposition à juste obtenir mon code pour fonctionner).

Voici ce que j'ai: -

using 
(
    TransactionScope transactionScope = 
     new TransactionScope 
     (
      TransactionScopeOption.RequiresNew, 
      new TransactionOptions 
       { IsolationLevel = IsolationLevel.ReadUncommitted } 
     ) 
) 
{ 
    _logEntryRepository.InsertOrUpdate(logEntry); 
    //_unitOfWork.Commit(); // Here, commit #1 ? 

    // Now, if this log entry was a NewConnection or an LostConnection, 
    // then we need to make sure we update the ConnectedClients. 
    if (logEntry.EventType == EventType.NewConnection) 
    { 
     _connectedClientRepository.Insert(
      new ConnectedClient { LogEntryId = logEntry.LogEntryId }); 
     //_unitOfWork.Commit(); // Here, commit #2 ? 
    } 

    // A (PB) BanKick does _NOT_ register a lost connection, 
    // so we need to make sure we handle those scenario's as a LostConnection. 
    if (logEntry.EventType == EventType.LostConnection || 
     logEntry.EventType == EventType.BanKick) 
    { 
     _connectedClientRepository.Delete(
      logEntry.ClientName, logEntry.ClientIpAndPort); 
     //_unitOfWork.Commit(); // Here, commit #3 ? 
    } 

    _unitOfWork.Commit(); // Here, commit #4 ? 
    transactionScope.Complete(); 
} 
+1

Je pense que vous êtes censé laisser l'unité de travail gérer les transactions ... –

+0

Je suppose que votre UOW est au courant de TransactionScope. Il devrait savoir quand s'engager en fonction du moment où vous commettez la transaction. – Ryan

+0

Cela dépend certainement de l'endroit où '_unitOfWork' est déclaré? –

Répondre

0

Commit à # 4 après toutes les opérations à tous les dépôts sont faits. Si vous vous engagez à l'avance, les modifications apportées après cet appel ne sont pas validées.

+0

Peut-être qu'il me manque quelque chose. Est-ce que _unitOfWork.Commit() est appelé plus tard dans le code? Il se peut que notre confusion réside dans le fait que UoW est sensible aux transactions, donc peu importe quand/si vous appelez Commit().Sinon, si elle n'est pas informée de la transaction et que les référentiels sont liés à UoW et que Commit() n'est pas appelé à nouveau, le travail ne modifiera que ce qui a été modifié dans le référentiel avant l'appel de Commit(). –

+0

Je viens de confirmer que l'UoW est sensible aux transactions -> il crée sa propre transaction Read Commited, donc je n'ai pas besoin de faire la mienne. Cela rend alors 100% plein de sens maintenant :) Le commit commence un tran, fait tous les changements (depuis le dernier commit) .. le pousse sur le db .. puis le comm. À votre santé! –

0

En supposant que votre magasin de données attribue des ID, vous devez valider # 1 (avec NHibernate vous devriez même vider), puis à la fin # 4.

3

Un bon point de départ pour répondre à cette question est la définition de l'unité de travail de modèles d'architecture d'entreprise (http://martinfowler.com/eaaCatalog/unitOfWork.html):

tient à jour une liste des objets touchés par une transaction commerciale et coordonne l'écriture sur changements et la résolution des problèmes de concurrence.

Les limites de votre unité de travail sont définies par les limites de votre transaction commerciale - dans ce cas, qui est synonyme avec les limites de la transaction de base de données (mais dans le cas d'une transaction commerciale à long en cours d'exécution couvrant plusieurs demandes qui peuvent ne pas être le cas).

À partir de la définition ci-dessus et en fonction de ma compréhension du code affiché, vous devez valider l'unité de travail à la fin de la transaction commerciale (# 4). En outre, vos portées de transaction de base de données doivent toujours être inférieures à la portée de votre UoW (c'est-à-dire que la portée tx réside entre l'appel à UoW.Begin() et UoW.Commit()). Si votre objet couvre plusieurs transactions de base de données, vous utiliseriez une transaction compensatrice pour "rééquilibrer" le UoW si l'une des transactions internes échouait. Dans ce cas, et surtout si votre UoW crée ses propres limites de transaction de base de données à UoW.Begin() et UoW.Commit(), je supprimerais la portée de la transaction car cela ajouterait simplement du bruit inutile au code.

+0

Grande réponse :) Et pour l'anecdote, EF fait cela sous le capot, quand vous * SubmitChanges() *. –

+0

Oui. Dans NH l'instance ISession est effectivement la UoW et iirc utilise la transaction associée pour déterminer quand un flush est requis - mais je ne suis pas tout à fait sûr sur ce point alors ne le prends pas à la banque =) – Neal

Questions connexes