Précédent   Forum des professionnels en informatique > Dotnet > Accès aux données
Accès aux données Forum d'entraide sur les technologies d'accès aux données de Microsoft (ADO.NET, Linq, Entity Framework, etc.).
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 08/02/2012, 18h23   #1
Invité de passage
 
Homme
Développeur .NET
Inscription : février 2012
Messages : 3
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations professionnelles :
Activité : Développeur .NET

Informations forums :
Inscription : février 2012
Messages : 3
Points : 1
Points : 1
Par défaut Transaction avec sqlTransaction en C#

Bonjour,

Je suis confronté à un problème dans un projet C# (windowsForm)

Je tente de mettre en place des transactions avant d'insérer des données en base Sql Server.
Il s'agit d'une application multi-utilisateurs et il est donc possible que plusieurs utilisateurs accèdent au même formulaire au même moment et insère des données différentes.
Le but étant de bloquer le second utilisateur si une transaction est déjà en cours.
J'ai bien conscience qu'il existe la mise en place des accès concurrentiels optimiste mais le projet existe déjà et la structure actuelle et le temp imparti ne me permettent pas de tout refaire d'où l'idée des transactions.

Je fais des tests en lancant 2 instances de Visual studio qui pointent sur la même solution.
Je met des points d'arret après avoir ouvert la transaction du 1er utilisateur puis je valide le formulaire pour le second utilisateur.

J'utilise un niveau d'isolation en serializable ou repeatableRead (j'ai essayé les 2) mais sans succès.

Avez vous une idée sur la faisabilité en utilisant les transactions ?

Voici l'extrait de code utilisé

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 
using (SqlConnection connection = new SqlConnection(ConfigurationManager.AppSettings["Main.ConnectionString"]))
                    {
                        connection.Open();
 
                        foreach (LotBL lot in lotsBL)
                        {
                            // Start a local transaction.
                            SqlTransaction transaction = connection.BeginTransaction(IsolationLevel.RepeatableRead ,"AllotLotSas");
 
                            try
                            {
								//Recupération des données en base avant insertion
                                ListAllotementBL AllotBLBdd = blAllotement.getAllotementsByLotByPPReseau(lot, ppIdReseau);
 
								//Comparaison d'objet pour vérifier que les données n'ont pas été mises à jour entre temps
                                if (AllotBLOrigin.Equals(AllotBLBdd))
                                {
									//Mise à jour des données
                                    if (!blAllotement.updateAllotements(updated, lot, ppIdReseau)) return;
                                }
                                else
                                {
                                    MessageBox.Show("L'allotement du lot a été modifié entre temps par un autre utilisateur.");
                                }
 
                                transaction.Commit();
 
                            }
                            catch (Exception ex)
                            {
                                transaction.Rollback("AllotLotSas");
                            }
                       }
                    }

Merci de votre aide.
filio est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 08/02/2012, 18h32   #2
Expert Confirmé Sénior
 
Homme François
Chef de projet NTIC
Inscription : janvier 2007
Messages : 5 370
Détails du profil
Informations personnelles :
Nom : Homme François
Âge : 51
Localisation : France

Informations professionnelles :
Activité : Chef de projet NTIC

Informations forums :
Inscription : janvier 2007
Messages : 5 370
Points : 9 781
Points : 9 781
Il semble que la connexion sur laquelle tu démarres une transaction n'est pas celle que tu utilises pour lire tes données, si j'en juge par ce bout de code.

Ceci explique cela.

Pour être précis, la connexion que tu ouvres et sur laquelle tu démarres une transaction, il semble que tu n'en fasses strictement rien.

Ou alors, il manque un bout du code.
__________________

Je ne réponds pas aux questions techniques par MP ! Le forum est là pour ça...


Une réponse vous a aidé ? utiliser le bouton

"L’ennui dans ce monde, c’est que les idiots sont sûrs d’eux et les gens sensés pleins de doutes". B. Russel
Bluedeep est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 09/02/2012, 09h40   #3
Invité de passage
 
Homme
Développeur .NET
Inscription : février 2012
Messages : 3
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations professionnelles :
Activité : Développeur .NET

Informations forums :
Inscription : février 2012
Messages : 3
Points : 1
Points : 1
Effectivement, la requête effectuée en base redéfinit une connexion donc elle n'est pas utilisée. Merci pour la remarque.

J'ai remplacé le bout de code par un sqlCommand comportant une requête select simple.
Le résultat est le même, les 2 transaction aboutissent alors que la 1ere n'est pas fermée.
En regardant dans la base sql server, j'ai bien 2 transaction en cours portant le même nom ('AllotLotSas') avec des id différents.

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
 
 using (SqlConnection connection = new SqlConnection(ConfigurationManager.AppSettings["Main.ConnectionString"]))
                    {
                       SqlCommand command = new SqlCommand();
                        command.Connection = connection;
                        connection.Open();
 
 
                        // Start a local transaction.
                        SqlTransaction transaction = connection.BeginTransaction(IsolationLevel.Serializable, "AllotLotSas");
 
                       command.Transaction = transaction;                            
 
 
                       command.CommandText = "select count(*) from dbo.Annexes where id_annexes = 46";
                            try
                            {
 
                                int test = (int)command.ExecuteScalar();
 
 
                                transaction.Commit();
 
                            }
                            catch (Exception ex)
                            {
                                transaction.Rollback("AllotLotSas");
                            }
 
                       }
filio est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 09/02/2012, 11h22   #4
Expert Confirmé Sénior
 
Homme François
Chef de projet NTIC
Inscription : janvier 2007
Messages : 5 370
Détails du profil
Informations personnelles :
Nom : Homme François
Âge : 51
Localisation : France

Informations professionnelles :
Activité : Chef de projet NTIC

Informations forums :
Inscription : janvier 2007
Messages : 5 370
Points : 9 781
Points : 9 781
Je ne comprends pas l'exemple que tu as choisi : en effet, ici, tu utilises une requête avec juste une fonction d'agrégat; cette requête ne retourne qu'un scalaire non susceptible de modification.

Il n'y a de ce fait aucun interêt à utiliser une transaction ici : cela ne sert à rien et n'aura aucun effet (le SGBD est quand même pas débile à ce point là !!!).

Je ne vois donc pas ce que tu peux tester avec cela.

C'est plutôt si une des deux requêtes restait bloquée qu'il faudrait s'inquiéter (et changer de SGBD dans ce cas )

Merci d'éclaircir ta demande.
__________________

Je ne réponds pas aux questions techniques par MP ! Le forum est là pour ça...


Une réponse vous a aidé ? utiliser le bouton

"L’ennui dans ce monde, c’est que les idiots sont sûrs d’eux et les gens sensés pleins de doutes". B. Russel
Bluedeep est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 09/02/2012, 11h47   #5
Invité de passage
 
Homme
Développeur .NET
Inscription : février 2012
Messages : 3
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations professionnelles :
Activité : Développeur .NET

Informations forums :
Inscription : février 2012
Messages : 3
Points : 1
Points : 1
Oui je me suis rendu compte qu'une requête select n'avais pas d'incidence.
J'ai fait le test avec une requête de mise à jour et effectivement cela fonctionne. tant que la 1ere transaction n'est pas validée, la seconde attend.

Je vais inclure une requête select qui récupère les données en base afin de vérifier que les données n'ont pas changées avant la mise à jour.

Merci pour ton aide.

Le post est résolu
filio est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 09/02/2012, 12h18   #6
Expert Confirmé Sénior
 
Homme François
Chef de projet NTIC
Inscription : janvier 2007
Messages : 5 370
Détails du profil
Informations personnelles :
Nom : Homme François
Âge : 51
Localisation : France

Informations professionnelles :
Activité : Chef de projet NTIC

Informations forums :
Inscription : janvier 2007
Messages : 5 370
Points : 9 781
Points : 9 781
Citation:
Envoyé par filio Voir le message
Oui je me suis rendu compte qu'une requête select n'avais pas d'incidence.
Si; une requête SELECT peut avoir une incidence (notamment avec l'option WITH ROWLOCK) mais pas dans ton exemple.
__________________

Je ne réponds pas aux questions techniques par MP ! Le forum est là pour ça...


Une réponse vous a aidé ? utiliser le bouton

"L’ennui dans ce monde, c’est que les idiots sont sûrs d’eux et les gens sensés pleins de doutes". B. Russel
Bluedeep est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 09/02/2012, 12h20   #7
Membre Expert
 
Homme Sylvain Devidal
Chef de projets Générix
Inscription : février 2010
Messages : 1 064
Détails du profil
Informations personnelles :
Nom : Homme Sylvain Devidal
Âge : 33
Localisation : France, Rhône (Rhône Alpes)

Informations professionnelles :
Activité : Chef de projets Générix
Secteur : High Tech - Éditeur de logiciels

Informations forums :
Inscription : février 2010
Messages : 1 064
Points : 1 515
Points : 1 515
Une requête select peut avoir une incidence, à condition de la forcer (utilisation de "with" pour imposer un mode de lock).

En fait, la question est : qu'est-ce que tu veux vraiment protéger ? Dans quel traitement, quelle cinématique ?

En effet, parfois tu n'as rien besoin de locker, et simplement faire les modifications sous forme de transaction. (mise à jour de la balance d'un compte en banque après saisie d'une commande par exemple)

Parfois, il faut locker dès la lecture des données pour s'assurer que personne ne viens modifier les données que tu modifies de ton côté. (mise à jour de la fiche d'un client par exemple)
StringBuilder est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité Cette discussion est résolue.
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 01h50.


 
 
 
 
Partenaires

Hébergement Web