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:
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>
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.
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:
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'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.
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:
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.
Et là ... je comprends du coup pas.
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 ?