2009-04-16 7 views
64

J'ai un morceau de code qui implique plusieurs insertions mais j'ai besoin d'exécuter la méthode submitchanges avant de terminer l'insertion dans d'autres tables afin de pouvoir acquérir un Id. J'ai cherché sur Internet et je ne pouvais pas trouver comment créer une transaction dans linq à sql. J'ai mis des commentaires dans le code où je veux que la transaction ait lieu.Comment créer une transaction LINQ to SQL?

var created = false; 
    try 
    { 
     var newCharacter = new Character(); 
     newCharacter.characterName = chracterName; 
     newCharacter.characterLevel = 1; 
     newCharacter.characterExperience = 0; 
     newCharacter.userUsername = userUsername; 
     newCharacter.characterClassID = ccslst[0].characterClassID; 
     //Open transaction 


      ydc.Characters.InsertOnSubmit(newCharacter); 
      ydc.SubmitChanges(); 

      foreach (var ccs in ccslst) 
      { 
       var cs = new CharacterStat(); 
       cs.statId = ccs.statID;       
       cs.statValue = ccs.statValue; 
       cs.characterID = newCharacter.characterID; 
       ydc.CharacterStats.InsertOnSubmit(cs); 
      }      


      var ccblst = ydc.ClassBodies.Where(cb => cb.characterClassID == newCharacter.characterClassID); 
      foreach (var ccb in ccblst) 
      { 
       var charBody = new CharacterBody(); 
       charBody.bodyId = ccb.bodyId; 
       charBody.bodyPartId = ccb.bodyPartId; 
       charBody.characterID = newCharacter.characterID; 
       ydc.CharacterBodies.InsertOnSubmit(charBody); 
      } 
      ydc.SubmitChanges();  
      created = true; 
     //Commit transaction 
     } 
     catch (Exception ex) 
     { 
      created = false; 
      //transaction Rollback;      
     } 
     return created; 

EDIT: Vous avez oublié de mentionner que ydc est mon datacontext

Répondre

65

Enroulez le tout dans un TransactionScope. Appelez transaction.Complete() au point où vous souhaitez valider. Si le code sort du bloc sans que Complete() soit appelé, la transaction sera annulée. Cependant, après avoir examiné la réponse de @ s_ruchit et réexaminé votre code, vous pourriez probablement réécrire ceci pour ne pas avoir besoin d'un TransactionScope. Le premier exemple utilise le TransactionScope avec votre code tel quel. Le second exemple apporte quelques modifications mineures, mais accomplit le même but.

Vous devez utiliser TransactionScope lorsque vous lisez une valeur dans la base de données et que vous l'utilisez pour définir une nouvelle valeur sur un objet ajouté. Dans ce cas, la transaction LINQ ne couvre pas la première lecture, juste l'envoi ultérieur de la nouvelle valeur. Puisque vous utilisez la valeur de la lecture pour calculer une nouvelle valeur pour l'écriture, vous avez besoin que la lecture soit enveloppée dans la même transaction pour s'assurer qu'un autre lecteur ne calcule pas la même valeur et évite votre changement. Dans votre cas, vous ne faites que des écritures de sorte que la transaction LINQ standard devrait fonctionner.

Exemple 1:

var created = false; 

using (var transaction = new TransactionScope()) 
{ 
    try 
    { 
     var newCharacter = new Character(); 
     newCharacter.characterName = chracterName; 
     newCharacter.characterLevel = 1; 
     newCharacter.characterExperience = 0; 
     newCharacter.userUsername = userUsername; 
     newCharacter.characterClassID = ccslst[0].characterClassID; 

     ydc.Characters.InsertOnSubmit(newCharacter); 
     ydc.SubmitChanges(); 

     foreach (var ccs in ccslst) 
     { 
      var cs = new CharacterStat(); 
      cs.statId = ccs.statID;       
      cs.statValue = ccs.statValue; 
      cs.characterID = newCharacter.characterID; 
      ydc.CharacterStats.InsertOnSubmit(cs); 
     }      

     var ccblst = ydc.ClassBodies.Where(cb => cb.characterClassID == newCharacter.characterClassID); 
     foreach (var ccb in ccblst) 
     { 
      var charBody = new CharacterBody(); 
      charBody.bodyId = ccb.bodyId; 
      charBody.bodyPartId = ccb.bodyPartId; 
      charBody.characterID = newCharacter.characterID; 
      ydc.CharacterBodies.InsertOnSubmit(charBody); 
     } 
     ydc.SubmitChanges();  
     created = true; 

     transaction.Complete(); 
    } 
    catch (Exception ex) 
    { 
     created = false; 
    } 
} 
return created; 

Exemple 2:

try 
    { 
     var newCharacter = new Character(); 
     newCharacter.characterName = chracterName; 
     newCharacter.characterLevel = 1; 
     newCharacter.characterExperience = 0; 
     newCharacter.userUsername = userUsername; 
     newCharacter.characterClassID = ccslst[0].characterClassID; 

     ydc.Characters.InsertOnSubmit(newCharacter); 

     foreach (var ccs in ccslst) 
     { 
      var cs = new CharacterStat(); 
      cs.statId = ccs.statID;       
      cs.statValue = ccs.statValue; 
      newCharacter.CharacterStats.Add(cs); 
     }      

     var ccblst = ydc.ClassBodies.Where(cb => cb.characterClassID == newCharacter.characterClassID); 
     foreach (var ccb in ccblst) 
     { 
      var charBody = new CharacterBody(); 
      charBody.bodyId = ccb.bodyId; 
      charBody.bodyPartId = ccb.bodyPartId; 
      newCharacter.CharacterBodies.Add(charBody); 
     } 
     ydc.SubmitChanges();  
     created = true; 
    } 
    catch (Exception ex) 
    { 
     created = false; 
    } 
+0

Vous ne savez pas sur la syntaxe, dois-je mettre mon code dans ce champ: à l'aide (TransactionScope ts = new TransactionScope()) { // mon code } – Drahcir

+0

Je l'ai ajouté à votre code et collé comme un exemple. – tvanfosson

+0

Cela a fonctionné, merci – Drahcir

38

Vous n'avez pas besoin de faire la mise en œuvre explicite de la transaction en utilisant LINQ to SQL. Toutes les opérations de base de données sont enveloppées dans une transaction par défaut.

Ex:

AppDataContext db = new AppDataContext(); 

<In memory operation 1 on db> 
<In memory operation 2 on db> 
<In memory operation 3 on db> 
<In memory operation 4 on db> 

db.SubmitChanges(); 

Toutes les opérations entre initialisation db DataContext et db.SubmitChanges() sont enroulés autour d'une opération de base de données par .Net assurant votre base de données pour être en cohérence et l'intégrité de la propriété entretenue à travers les tables.

Lire un article Par Scott Guthriehere: - http://weblogs.asp.net/scottgu/archive/2007/07/11/linq-to-sql-part-4-updating-our-database.aspx

+0

Mais j'avais besoin d'un ID qui a été généré sur le premier soumettre des modifications, ne savait pas autrement comment acquérir l'ID. – Drahcir

+3

Visitez l'article écrit par ScottGu. Vous pouvez associer sans l'ID. C'est la beauté de LINQ-to-SQL. Si vous ne le faites pas, vous n'utilisez pas le Linq-To-Sql. Je vous recommande de lire l'article de ScottGu. Vous pouvez trouver le lien dans ma réponse. –

+0

Oui. Il semble que vous pourriez réécrire cela pour ne pas avoir besoin d'une transaction externe. Je vais mettre à jour ma réponse. – tvanfosson