La première question que je voudrais poser est: ai-je vraiment besoin de faire cela du tout? Le concepteur DataSet typé vous donne déjà un outil pour définir le mappage entre une procédure stockée et un DataTable. Si vous concevez votre DataSet avec soin, vous avez déjà une méthode Fill pour chaque DataTable. Est-ce logique de réinventer cette roue?
Je pense que cela pourrait. C'est vraiment cool qu'il y ait un moyen de maintenir ce mapping, mais tout dans ce mapping est gelé au moment de la compilation. Si vous souhaitez modifier le mappage, vous devez reconstruire votre assembly. La conception DataSet typée ne traite pas non plus des procédures stockées qui renvoient plusieurs ensembles de résultats. Si vous souhaitez mapper génériquement des paramètres et des valeurs, vous devez utiliser la réflexion pour obtenir les listes d'arguments à partir des méthodes Fill. Il se peut que si vous regardez ces facteurs (et d'autres auxquels je ne pense pas), travailler avec l'outil existant n'est pas la bonne solution.
Dans ce cas, il me semble que votre objectif est de pouvoir remplir un DataSet à partir d'une série de procédures stockées avec un code qui en sait le moins possible sur les détails d'implémentation. C'est donc un processus qui va être piloté par des métadonnées. Lorsque vous avez un processus piloté par des métadonnées, ce qui vous importe le plus à long terme, c'est combien il sera facile de gérer les métadonnées utilisées par le processus. Une fois que le code fonctionnera, vous ne le toucherez probablement pas beaucoup. Mais vous allez peaufiner les métadonnées en permanence.
Si je regarde le problème de ce point de vue, la première chose que je pense faire est de concevoir un DataSet typé pour contenir les métadonnées. Cela nous donne un tas de choses que nous avions autrement à comprendre:
- un format de persistance
- un chemin facile à construire une interface utilisateur liée
- un chemin tout aussi simple à la persistance des métadonnées dans un base de données si nous décidons de descendre cette route
- un modèle d'objet pour la navigation des données.
Dans ce DataSet, vous disposez d'une table DataSetType, indexée sur le Type de chaque DataSet typé que vous avez l'intention de renseigner. Il aurait une table StoredProcedures enfant, avec une ligne pour chaque SP appelé. Cela aurait deux tables enfants, Parameter et DataTableType. Il y aurait une rangée DataTableType, ordonnée par position ordinale, pour chaque ensemble de résultats que le SP devrait retourner. La table DataTableType aurait une table ColumnMapping enfant. C'est dans cette table que vous gérez les mappages entre les colonnes du jeu de résultats et les colonnes de la table que vous remplissez. Assurez-vous que toutes vos DataRelations sont imbriquées et que vous avez donné des noms rationnels aux relations. (J'aime FK_childtablename_parenttablename
.)
Une fois que vous avez cela, la conception de la classe devient assez simple. La classe a une référence au DataSet de métadonnées, la connexion, etc ,, et il expose une méthode avec cette signature.
public void FillDataSet(DataSet targetDs, Dictionary<string, Dictionary<string, KeyValuePair<string, string>> parameterMap);
Vous commencez en utilisant le type de l'targetDs pour trouver la ligne de DataSetType haut niveau. Ensuite, toutes les méthodes privées parcourent les listes de DataRows renvoyées par DataTable.GetChildRows(). Et vous ajoutez un ou deux événements à la conception de classe, de sorte que, lors de l'exécution de l'opération, elle peut déclencher des événements pour que l'application appelante sache comment elle progresse.
Probablement le premier endroit que je m'attendrais à refactoriser cette conception est de me donner un contrôle plus fin sur le processus de remplissage. Par exemple, comme prévu, il n'y a qu'un seul ensemble de SP par DataSet typé. Que faire si je veux seulement remplir un sous-ensemble du DataSet? Comme prévu, je ne peux pas. Mais vous pouvez facilement rendre la clé primaire de la table DataSetType en deux parties, les parties étant un type DataSet et une clé de chaîne (avec un nom comme SPSetName ou OperationName) et ajouter la deuxième partie de la clé à la liste d'arguments FillDataSet .
Quel mécanisme utilisez-vous pour remplir les différents DataTables? Un DataReader? TableAdapters? Autre chose? –
J'utilise SqlDataAdapters. J'ai mis à jour la question pour que ce soit clair. :) –