Glop à vous.
Ma première question concerne un petit problème que je rencontre au boulot.
Sql Server 2005 permet de manipuler le xml, mais dans ce domaine, et bien disons que... en T-SQL, il n'est pas vraiment performant
(ou alors je m'y suis vraiment pris comme un pied )
J'ai donc besoin de créer un xml qui a globalement cette forme:
Générer ce xml depuis une requête T-SQL est coûteux, aussi, il avait été décidé de passer par le CLR pour le générer.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 <liste AL1 = "" AL2=""> <article A1 = ""> <status> <!-- balise non répétable et même potentiellement vide --> <s lib="" /> </status> <meta desc=""> <val key="" v=""/> </meta> </article> </liste>
On a rencontrer un problème (genre out of memory) avec l'implémentation en proc CLR (qui chargeait toutes les données et y allait à coups de DataTable.Select()), aussi j'ai essayé d'améliorer les choses en essayant de passer par une fonction table.
J'ai réussi (le test de charge est pour demain), toutefois j'ai rencontré quelques difficultés (et c'était ma première tentative en CLR Sql Server).
Tout d'abord, j'ai été ennuyé de ne pas pouvoir ouvrir plusieurs connections afin de lancer 2 ou 3 DataReader en parallèle (pour minimiser la consommation mémoire), mais bon, bon-gré mal-gré, j'ai contourné ça.
En gros, voilà comment fonctionne mon code:
J'avais aperçu un ou deux codes où on ne faisait pas un return "bête et méchant" dans la méthode d'init, mais un yield return.
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 class myobj { clé; XmlDocument; myobj() {} myobj(k, x) {}; } méthode static IEnumerable init(myparam): DataReader liste -> dataTable liste ArrayList res; // si je me souviens bien, ça doit être un type de ce genre foreach (DataRow in liste.Rows) { x = new XmlDocument construction nœud principal DataReader item --> nœud item DataReader dr_status if (dr_status.HasRows) { nœud status while (dr_status.Read()) création nœud s } DataReader meta --> DataTable metas foreach (DataRow in metas.Rows) { nœud meta DataReader val --> nœud val } res.Add(new myobj(clé, x)); } return res; methode FillRow(object source, les colonnes SqlTypées){ //peu importe non ? ;) }
J'ai donc essayé d'enlever les 2 lignes en orange ci-dessus en remplaçant l'ajout à l'ArrayList par un yield return new myobj(clé, x);
Mon idée était d'essayer de linéariser la génération des données et leur "consommation" par le FillRow.
Hélas, je me suis pris cette exception:
Et là ... je comprends du coup pas.System.InvalidOperationException: Data access is not allowed in this context. Either the context is a function or method not marked with DataAccessKind.Read or SystemDataAccessKind.Read, is a callback to obtain data from FillRow method of a Table Valued Function, or is a UDT validation method.
comment on doit faire pour pouvoir utiliser le yield ici ?
ou alors quand peut-on l'utiliser dans une SqlFunction ?
édit: voilà un lien msdn où j'avais vu ce fameux yield return ...page msdn
Sinon, j'ai une deuxième question, très certainement liée à mon mauvais niveau d'anglais...
J'ai lu quelques petites choses dessus, mais je n'ai pas compris l'utilité du SqlPipe
Quel est l'exemple "ultime" qui permet de se rendre compte d'à quoi ça sert de manière qu'on hésite plus sur son rôle ?
Partager