TransactionScope et Entity Framework

by Nicolas Calvi 6. novembre 2009 16:43

J'ai récemment contribué à un projet qui met en place Entity Framework et je suis arrivé sur une problématique intéressante. En effet, dans un de mes traitements je dois insérer et modifier des données (appelons cette donnée D) en passant par Entity Framework. Le problème est qu'après chaque création d'une entité D dans le Context, un peu plus loin dans mon processus, je fais une requête Linq To Entity pour tester l'existance de cette donnée D dans la base donnée. Malheureusement, si la fonction Context.SaveChanges() n'a pas invoquée, la donnée n'est pas poussée en base et donc ne peut être ramenée dans ma sélection avec Linq To Entity.


Il existe une méthode pour requêter le Context et donc prendre en compte l'entité D nouvellement créée. Cependant, cela revient à faire deux requêtes, une dans le Context des objets non mis à jour et l'autre dans la base de données. Pour plusieurs raisons (factorisation du code notamment) cette solution n'était pas satisfaisante. Or je ne pouvais pas non plus invoquer la fonction Context.SaveChanges() car mon traitement est long et j'ai une exigence d'intégrité des données qui me force à faire un Rollback au moindre problème, or faire des Context.SaveChanges() répétés fait une mise à jour non réversible et donc incompatible avec mon exigeance.


J'ai donc décidé de tester de mettre mon traitement dans un TransactionScope pour voir si l'invocation de Context.SaveChanges() pouvais être transactionnel et la réponse est oui. En effet, cette technique me permet de valider mes entités D en base tout en ayant la possibilité de faire un Rollback. Le fait qu'Entity Framework offre cette possibilité permet une plus grande flexibilité dans son utilisation.

public void FonctionDeTest()
{
  MyEntities context = new MyEntities();

  using ( TransactionScope scope = new TransactionScope() )
  {
    // Faire un traitement avec EF
    context.SaveChanges();

    // Faire d'autres traitement avec EF
    context.SaveChanges();

    // Validation de la transaction
    scope.Complete();
  }

  context.Dispose();
}