J'écris un test d'intégration dans lequel j'insérerai un certain nombre d'objets dans une base de données, puis je vérifierai si ma méthode récupère ces objets.
Ma connexion à la base de données se fait via NHibernate ... et ma méthode habituelle pour créer un tel test serait de faire ce qui suit:
NHibernateSession.BeginTransaction();
//use nhibernate to insert objects into database
//retrieve objects via my method
//verify actual objects returned are the same as those inserted
NHibernateSession.RollbackTransaction();
Cependant, j'ai récemment découvert TransactionScope qui peut apparemment être utilisé à cette fin ...
Un exemple de code que j'ai trouvé est le suivant:
public static int AddDepartmentWithEmployees(Department dept)
{
int res = 0;
DepartmentAdapter deptAdapter = new DepartmentAdapter();
EmployeeAdapter empAdapter = new EmployeeAdapter();
using (TransactionScope txScope = new TransactionScope())
{
res += deptAdapter.Insert(dept.DepartmentName);
//Custom method made to return Department ID
//after inserting the department "Identity Column"
dept.DepartmentID = deptAdapter.GetInsertReturnValue();
foreach(Employee emp in dept.Employees)
{
emp.EmployeeDeptID = dept.DepartmentID;
res += empAdapter.Insert(emp.EmployeeName, emp.EmployeeDeptID);
}
txScope.Complete();
}
return res;
}
Je crois que si je n'inclus pas la ligne txScope.Complete()
, les données insérées seront annulées. Mais malheureusement , je ne comprends pas comment cela est possible ... comment l' txScope
objet garder une trace du deptAdapter
et des empAdapter
objets et de leurs transactions sur la base de données.
J'ai l'impression qu'il me manque un peu d'informations ici ... Suis-je vraiment capable de remplacer mes appels BeginTransaction()
et RollbackTransaction(
) en entourant mon code en utilisant TransactionScope
?
Sinon, comment TransactionScope
fonctionne-t-il pour annuler les transactions?
Réponses:
Essentiellement, TransactionScope ne suit pas votre adaptateur, il suit les connexions à la base de données. Lorsque vous ouvrez une connexion DB, les connexions recherchent s'il existe une transaction ambiante (Transaction Scope) et si c'est le cas, s'enrôlent avec elle. Attention, s'il existe plusieurs connexions au même serveur SQL, cela se transformera en une transaction distribuée.
Que se passe-t-il puisque vous utilisez un bloc using, vous vous assurez que dispose sera appelé même si une exception se produit. Donc, si dispose est appelé avant txScope.Complete (), le TransactionScope indiquera aux connexions d'annuler leurs transactions (ou le DTC).
la source
La
TransactionScope
classe travaille avec laTransaction
classe , qui est spécifique au thread.Lorsque le
TransactionScope
est créé, il vérifie s'il existe unTransaction
pour le thread; s'il en existe un, il l'utilise, sinon, il en crée un nouveau et le pousse sur la pile.S'il en utilise un existant, il incrémente simplement un compteur pour les versions (puisque vous devez l'appeler
Dispose
). Sur la dernière version, si leTransaction
n'était pas engagé, il annule tout le travail.Quant à savoir pourquoi les classes semblent savoir par magie sur les transactions, cela reste un détail d'implémentation pour les classes qui souhaitent travailler avec ce modèle.
Lorsque vous créez vos instances
deptAdapter
etemptAdapter
, ils vérifient s'il existe une transaction en cours sur le thread (laCurrent
propriété statique de laTransaction
classe). Si tel est le cas, il s'enregistre auprès duTransaction
, pour prendre part à la séquence de validation / annulation (quiTransaction
contrôle et pourrait se propager à différents coordinateurs de transaction, tels que le noyau, distribué, etc.).la source