Bonjour,

Comment peut on créer et gérer des savepoints Oracle au seing d'un TransactionScope :

Tout d'abord une description de l'environnement : Oracle 10g avec OracleProvider (ODAC 2.102.2.20) client C# 3.0.

Jusqu'à présent nous avions un code classique de sauvegarde de documents ou de paramètres où nous placions des savepoints réguliers afin que si la sauvegarde d'un document échoue elle ne mette pas en péril l'ensemble de la sauvegarde.

Voici un petit exemple de code :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
 
 
//Ceci est ma liste de Custom Object 
List<GeneralParameterValue> list = new  List<GeneralParameterValue>();
 
           //Je créé un obj que je rajoute dans la liste 
           GeneralParameterValue value1 = new GeneralParameterValue();
            value1.GPR_CODE = param.GPR_CODE;
            value1.GPR_CODE_SOURCE = param;
            value1.SCP_DATE = DateTime.Today;
            value1.SCP_VALUE = "10";
            list.Add(value1);
 
            //Un second
            GeneralParameterValue value2 = new GeneralParameterValue();
            value2.GPR_CODE = param.GPR_CODE;
            value2.GPR_CODE_SOURCE = param;
            value2.SCP_DATE = DateTime.Today.AddDays(1);
            value2.SCP_VALUE = "20";
            list.Add(value2);
 
 
           //DataProvider est un OracleConnection en singleton.
          // Je créé donc une nouvelle connexion Oracle    
          DataProvider provider = new DataProvider();
 
           //Démarrage de la transaction
            provider.BeginTransaction();
            try
            {
                {
 
//Mon provider fait l'Insert ou l'update en fonction de l'état de l'objet.                   
 GeneralParameterValueDataProvider gvProvider = new GeneralParameterValueDataProvider();
 
                    //Définition d'un SavePoint
                    string savePoint = "Hello";
                    provider.SetSavePoint(savePoint);
 
                    gvProvider.Save(provider.Connection, value1);
 
                    //On RollBack jusqu'au précédent savepoint 
                    provider.Rollback(savePoint);
 
                    gvProvider.Save(provider.Connection, value2);
 
                  //On commit l'ensemble de la transaction sauf ce qui a été annulé par le rollBack du Savepoint
                   provider.Commit();
                }
            }
            catch (Exception exception)
            {
                provider.Rollback();
                Debug.WriteLine(exception.Message);
            }
            finally
            {
                provider.EndTransaction(); //Termine la transaction et coupe la connexion
            }

Depuis peu nous avons modifié notre code pour rendre nos custom Objects transactionnels afin que lorsqu'une transaction est annulée nos objets reviennent aussi à l'état initial (et non pas seulement la DB). Pour cela nous implémentons l'interface ISinglePhaseNotification.


Ma procédure actuelle de sauvegarde ressemble donc à ceci :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
36
37
38
39
40
41
42
43
44
45
46
 
List<GeneralParameterValue> list = new List<GeneralParameterValue>();
 
            GeneralParameterValue value1 = new GeneralParameterValue();
            value1.GPR_CODE = param.GPR_CODE;
            value1.GPR_CODE_SOURCE = param;
            value1.SCP_DATE = DateTime.Today;
            value1.SCP_VALUE = "10";
            list.Add(value1);
 
            GeneralParameterValue value2 = new GeneralParameterValue();
            value2.GPR_CODE = param.GPR_CODE;
            value2.GPR_CODE_SOURCE = param;
            value2.SCP_DATE = DateTime.Today.AddDays(1);
            value2.SCP_VALUE = "20";
            list.Add(value2);
 
 
            DataProvider provider = new DataProvider();
            try
            {
               //utilisation d'un trasactionScope 
               using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
                {
 
                    GeneralParameterValueDataProvider gvProvider = new GeneralParameterValueDataProvider();
 
                   //Comment peut on definir un savePoint ici car je n'ai pas la main sur l'OracleTransaction qui s'est créé implicitement lors de l'enregistrement dans le scope.      
 
                    gvProvider.Save(provider.Connection, value1);
 
                   //Comment rollBacker ici jusqu'au savepoint?
 
                    gvProvider.Save(provider.Connection, value2);
 
                    scope.Complete();            
                }
            }
            catch (Exception exception)
            {
                Debug.WriteLine(exception.Message);
            }
            finally
            {
                provider.Connection.Close();
            }
Bien entendu, il est possible de décorréler la transaction Oracle et le transactionScope en faisant un mixte de ces deux code c'est à dire créer une connexion et une transaction Oracle avant le TransactionScope et donc ne pas l'inscrire dans le scope et gérer à la mano l'appel du commit avant le scope.Complete et de faire appel au rollback dans le catch.

Seulement cette solution ne me plait pas vraiment, je souhaiterai une gestion plus simple ou en tout cas plus intégrée au TransactionScope.

Avez vous déjà rencontré ce cas?

Merci