Bonjour,
Je butte sur un cas un peu spécial à l'heure actuelle.
J'ai un projet avec EntityFramework (VS2010) avec utilisation d'entités POCO.
j'ai un type abstrait Horaire, et deux types spécialisant Realisee et Planifiee.
J'ai deux vues qui permette de créer des horaires réalisées, pour des raisons différentes.
Le total d'horaires actuel dans la base de données doit tourner dans les 20000.
Quand j'ajoute des horaires réalisées par la vue 1...
je fait naturellement ctx.Horaires.AddObject(r) où r est une instance de Realisee que je viens à l'instant d'instancier, et après je lui affecte ses liens vers d'autres tables.
L'opération totale pour 1 ou 20 horaires prend 1s (il y a toute une série de traitements nécessaires, et de contrôles)
En revanche quand je passe sur la vue 2... même circonstances, fonctionnement similaire, et là au premier appel à ctx.Horaires.AddObject(r) prend 3mn, les suivants sont instantannés mais le premier est atrocement long.
j'ai revérifié l'autre vue et j'ai toujours 1s... c'est toujours pareil, et le code est similaire, la seule différence, ce situe au niveau du contenue de heures réalisées...
elles possède un tag fromYP booléen que je met à false pour les horaires de la vue 1 et à true pour la vue 2, mais même mettant false dans la vue 2... j'ai toujours le même délai.
malheureusement il m'est impossible d'utiliser la méthode d'ajout de la vue 1 dans la 2. car dans le cas de la 2 j'ai des prétraitement supplémentaire à effectuer avant de créer les réalisées, comme retrouver le tarif de celles ci.
j'ai détaillé mes temps avec des Stopwatch, et c'est bien le AddObject qui pète un cable dans le cas de la vue 2.
Si quelqu'un peut m'expliquer pourquoi dans une méthode ça prend rien et dans l'autre ça prend 3mn avec utilisation full du thread => 1 core CPU blindé a 100%... je suis tout ouie.
voici du code pour ceux que ça intéresse :
méthode 1 :
Code C# : 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 using (var ctx = new DataContainer()) { var regp = horaires.GroupBy( x => x.Formateur.ID ); foreach (var gh in regp) { var f = ctx.Formateurs.Single( x => x.ID == gh.Key ); foreach (var h in gh) { if (h.Prix > 0) { Realisee r = new Realisee() { Date = h.Date, Duree = h.Duree, Prix = h.Prix, fromYP = false, Link = h.Link }; var m = ctx.Matieres.Single( x => x.ID == h.Matiere.ID ); var s = ctx.Sessions.Single( x => x.ID == h.Session.ID ); var l = ctx.Sites.Single( x => x.ID == h.Site.ID ); var stat = ctx.Statuts.Single( x => x.ID == h.Statut.ID ); ctx.Horaires.AddObject( r ); r.Formateur = f; r.Matiere = m; r.Session = s; r.Site = l; r.Statut = stat; } } // Sauvegarde sinon rebuildAll ne collectera aucune horaire pour créer les validations. ctx.SaveChanges(); rebuildAll( f, ctx ); ctx.SaveChanges(); } ctx.SaveChanges(); }
et la seconde méthode...
le code n'est pas définitif et n'est pas propre car il a déjà changé une 10ene de fois depuis que j'ai repéré le problème... c'est assez récent d'ailleurs, au début le comportement était similaire et les temps identiques.
w est une stopwatch, et les cacheX sont des dictionnaires.
Code C# : 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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88 using (var ctx = new DataContainer()) { var regp = horaires.GroupBy( x => x.Formateur.ID ); foreach (var gh in regp) { var f = ctx.Formateurs.Single( x => x.ID == gh.Key ); foreach (var h in gh) { w = Stopwatch.StartNew(); var prix = h.Prix; Statut t = null; if (!cacheT.TryGetValue( h.Formateur.ID, out t )) cacheT.Add( h.Statut.ID, t = ctx.Statuts.Single( x => x.ID == h.Statut.ID ) ); Session s = null; if (!cacheS.TryGetValue( h.Session.ID, out s )) cacheS.Add( h.Session.ID, s = ctx.Sessions.Single( x => x.ID == h.Session.ID ) ); Matiere m = null; if (!cacheM.TryGetValue( h.Matiere.ID, out m )) cacheM.Add( h.Matiere.ID, m = ctx.Matieres.Single( x => x.ID == h.Matiere.ID ) ); w.Stop(); tr.AppendFormat( "cache 1: {0}\n", w.Elapsed ); w = Stopwatch.StartNew(); if (prix == 0) { var key = string.Format( "{0}.{1}.{2}", t.ID, h.Session.ID, h.Matiere.ID ); if (!cacheP.TryGetValue( key, out prix )) { // Dans ce cas on recherche le prix dans la grille tarifaire de ARCA var taux = PricingMgr.Instance.GetRate( t.TypeStatut, s, m, ctx ); if (taux != null) prix = taux.PrixHoraire; cacheP.Add( key, taux != null ? prix : 0 ); } } w.Stop(); tr.AppendFormat( "prix: {0}\n", w.Elapsed ); if (prix > 0) { //h.Realisation = 1; // marque l'horaire comme réalisée, ce marquage a lieue séparémment w = Stopwatch.StartNew(); // Création de l'heure réalisée idoine Realisee r = new Realisee() { Date = h.Date, Duree = h.Duree, Prix = h.Prix, fromYP = true, Link = h.ID }; Site l = null; if (!cacheL.TryGetValue( h.Site.ID, out l )) cacheL.Add( h.Site.ID, l = ctx.Sites.Single( x => x.ID == h.Site.ID ) ); w.Stop(); tr.AppendFormat( "cache 2: {0}\n", w.Elapsed ); w = Stopwatch.StartNew(); ctx.Horaires.AddObject( r ); // cette opération prend 3mn lors de la première insertion. Uniquement dans cette méthode. w.Stop(); r.Formateur = f; r.Matiere = m; r.Session = s; r.Site = l; r.Statut = t; tr.AppendFormat( "ajout: {0}\n", w.Elapsed ); } else lid.Add( h.ID ); } ctx.SaveChanges(); rebuildAll( f, ctx ); ctx.SaveChanges(); } }
lid une liste d'entiers.
tr un stringbuilder.
c'est le premier et dernier projet où j'utilise EF Avec les POCO... j'ai accumulé trop d'emmerdes avec... des comportements bizarres non documentés, j'en ai eu des tas, comme des relations *-* non persisté parce que l'ajout de liens dans les collection de l'un et l'autre n'était pas détectés, malgré l'utilisation des proxy dans les contextes...
cela m'apprendra à vouloir innover !
Partager