69 votes

Comment créer une transaction LINQ to SQL ?

J'ai un morceau de code qui implique des insertions multiples mais j'ai besoin d'exécuter la méthode submitchanges avant de finir d'insérer dans d'autres tables afin de pouvoir acquérir un Id. J'ai fait des recherches sur Internet et je n'ai pas trouvé comment créer une transaction dans linq to sql. J'ai mis des commentaires dans le code où je veux que la transaction ait lieu.

    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 : J'ai oublié de mentionner que ydc est mon contexte de données.

71voto

tvanfosson Points 268301

Enveloppez le tout dans un TransactionScope . Appelez transaction.Complete() à l'endroit où vous voulez valider. Si le code sort du bloc sans Complete() est appelé, la transaction sera annulée. Cependant, après avoir lu la réponse de @s_ruchit et réexaminé votre code, vous pourriez probablement le réécrire de manière à ne pas exiger un fichier TransactionScope . Le premier exemple utilise le TransactionScope avec votre code tel quel. Le deuxième exemple apporte quelques changements mineurs, mais accomplit le même objectif.

Un endroit où vous auriez besoin d'utiliser le TransactionScope c'est 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 qui est ajouté. Dans ce cas, la transaction LINQ ne couvrira pas la première lecture, mais seulement la soumission ultérieure 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 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, donc 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 votes

Je ne suis pas sûr de la syntaxe, dois-je mettre mon code dans cette portée : using (TransactionScope ts = new TransactionScope()) { /mon code }

2 votes

Vous aurez besoin du service DTC pour fonctionner sur la machine de déploiement pour effectuer des transactions en utilisant TransactionScope. Gardez cela à l'esprit. DTC : Service de coordination des transactions distribuées.

0 votes

@s_ruchit -- En fait, je ne suis pas sûr qu'avec LINQ, il sera promu à une transaction distribuée. Puisque le contexte de données utilise la même connexion pour toutes les soumissions, je pense que cela restera local. C'est différent de l'utilisation des TableAdapters.

44voto

this. __curious_geek Points 23728

Il n'est pas nécessaire d'effectuer une mise en œuvre explicite des transactions lors de l'utilisation de LINQ to SQL. Toutes les opérations de la 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 l'initialisation du DataContext de db et db.SubmitChanges() sont enroulées autour d'une transaction de base de données par .Net, ce qui garantit la cohérence de votre base de données et le maintien de l'intégrité des propriétés entre les tables.

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

0 votes

Mais j'avais besoin d'un identifiant qui a été généré lors de la première soumission des modifications, je ne savais pas comment obtenir cet identifiant.

4 votes

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

0 votes

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

-1voto

Paul Nakitare Points 97

EF6 fournit Database.BeginTransaction() - une méthode plus simple permettant à un utilisateur de lancer et d'achever lui-même des transactions au sein d'un contexte de données existant - ce qui permet de combiner plusieurs opérations au sein d'une même transaction et donc de les valider ou de les annuler en une seule fois. Elle permet également à l'utilisateur de spécifier plus facilement le niveau d'isolement de la transaction. DbContextTransaction.Commit() effectue un commit sur la transaction du magasin sous-jacent alors que la méthode DbContextTransaction.Rollback() effectue un retour en arrière sur la transaction de stockage sous-jacente.

var created = false;
using (var ydc = new CustomContext())
{
    using (var dbContextTransaction = ydc.Database.BeginTransaction())
    {
        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
            dbContextTransaction.Commit();
        }
        catch (Exception ex)
        {
            created = false;
            // Rollback transaction
            dbContextTransaction.Rollback();
        }
    }
}
return created;

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X