none
Dataset sans ODBC

    Question

  • Bonjour tout le monde,

    Par défaut, quand on crée un Dataset dans l'éditeur ad hoc sous Visual Studio, on obtient quelque chose qui exploite l'ODBC.

    Or, dans mon projet je me rends compte que l'ODBC présente quelques problèmes de déploiement. Il faut réussir à faire cohabiter harmonieusement ODBC 32 bits avec ODBC 64 bits, et ce n'est pas toujours "de la tarte". Mon client en est même arrivé à ne plus pouvoir faire fonctionner l'ancienne application depuis qu'il a voulu mettre à jour l'ODBC de sa machine.

    Quand on veut installer ODBC sur une machine, sauf à recourir à des sites de téléchargement sauvages dont l'expérience montre qu'ils sont susceptibles d'ajouter des bricoles à eux, on arrive chez Microsoft qui en tête de résultats de recherche propose d'installer MDAC ... et en y regardant d'un peu plus près MDAC ne revendique pas de compatibilité avec Windows 10, que Microsoft présente pourtant comme la panacée à utiliser de manière universelle.

    Alors, comme j'ai un pilote pgsql qui fonctionne pas trop mal sur une base PostgreSql (et ça s'est trouvé comme ça mais le raisonnement aurait été le même avec SQL Server), pour ne pas avoir de problème de déploiement mais exploiter la commodité des Datasets, ça serait quand même pas mal de pouvoir en créer un avec le pilote concerné.

    S'agit-il d'une lubie de ma part, ou est-ce qu'on peut bénéficier de l'interface de création de Datasets sans recourir à ODBC ?

    Ou ça risque d'être plus raisonnable de l'envisager par code ?

    lundi 19 février 2018 14:13

Réponses

  • Bonjour,

    Je crois que j'ai trouvé l'explication, toute simple.

    Revenons-en aux basiques pour comprendre. Pour créer un Dataset, je fais un clic droit sur le projet, puis je clique "Ajouter, nouveau". Dans la catégorie Données, je choisis DataSet.

    J'arrive sur la surface du concepteur, avec dans l'onglet le titre DataSet1.xsd

    A partir de l'explorateur de serveurs, je trouve la table qui m'intéresse, et je la fais glisser vers la surface du concepteur.

    Etant parti, dans l'explorateur de serveurs, d'une connexion disponible en ODBC, j'ai trouvé dans le code de DataSet1.Designer.cs :

            internal global::System.Data.Odbc.OdbcConnection Connection {
                get {
                    if ((this._connection == null)) {
                        this.InitConnection();
                    }
                    return this._connection;
                }
                set {
                    this._connection = value;
                    if ((this.Adapter.InsertCommand != null)) {
                        this.Adapter.InsertCommand.Connection = value;
                    }
                    if ((this.Adapter.DeleteCommand != null)) {
                        this.Adapter.DeleteCommand.Connection = value;
                    }
                    if ((this.Adapter.UpdateCommand != null)) {
                        this.Adapter.UpdateCommand.Connection = value;
                    }
                    for (int i = 0; (i < this.CommandCollection.Length); i = (i + 1)) {
                        if ((this.CommandCollection[i] != null)) {
                            ((global::System.Data.Odbc.OdbcCommand)(this.CommandCollection[i])).Connection = value;
                        }
                    }
                }
            }


    Pour le cas où je serais tenté de faire la correction à ce niveau, je trouve en tête de fichier l'avertissement :

    // <auto-generated>
    //     Ce code a été généré par un outil.
    //     Version du runtime :4.0.30319.42000
    //
    //     Les modifications apportées à ce fichier peuvent provoquer un comportement incorrect et seront perdues si
    //     le code est régénéré.
    // </auto-generated>

    Si maintenant, lors de la création du DataSet avec l'interface graphique, au lieu de glisser une table depuis une connexion ODBC, je glisse une table depuis une connexion PGSQL, j'obtiens :

            internal global::Devart.Data.PostgreSql.PgSqlConnection Connection {
                get {
                    if ((this._connection == null)) {
                        this.InitConnection();
                    }
                    return this._connection;
                }
                set {
                    this._connection = value;
                    if ((this.Adapter.InsertCommand != null)) {
                        this.Adapter.InsertCommand.Connection = value;
                    }
                    if ((this.Adapter.DeleteCommand != null)) {
                        this.Adapter.DeleteCommand.Connection = value;
                    }
                    if ((this.Adapter.UpdateCommand != null)) {
                        this.Adapter.UpdateCommand.Connection = value;
                    }
                    for (int i = 0; (i < this.CommandCollection.Length); i = (i + 1)) {
                        if ((this.CommandCollection[i] != null)) {
                            ((global::Devart.Data.PostgreSql.PgSqlCommand)(this.CommandCollection[i])).Connection = value;
                        }
                    }
                }
            }

    La réponse à la question était donc :

    faire attention à la connexion choisie dans l'explorateur de serveurs, au cours de l'utilisation de l'interface graphique du concepteur de DataSet de Visual Studio.



    • Marqué comme réponse Gloops jeudi 1 mars 2018 10:43
    • Modifié Gloops jeudi 1 mars 2018 10:46
    jeudi 1 mars 2018 10:42

Toutes les réponses

  • Bon, voilà où j'en suis là-dessus : il faut l'ODBC sur la machine de développement pour pouvoir utiliser l'interface graphique de création de Dataset.

    Ce que l'ODBC peut poser comme problème, c'est le déploiement. Sur quatre machines tentées, quatre problèmes différents.

    En revanche ce n'est plus un problème si on accède aux données par code à l'aide d'un accès .Net.

    Je crée un DataAdapter (dans le cas de PostgreSql, "new NpgsqlDataAdapter(" ; pour Sql Server si je me rappelle bien, SqlDataAdapter), avec en premier argument la requête SQL, en deuxième la chaîne de connexion. Ensuite, le DataAdapter, avec sa méthode Fill, peut remplir le Dataset.

    Du moment que chaque Dataset est rempli comme ça avant l'affichage du formulaire, les accès ODBC ne sont pas sollicités, donc on n'a pas de problème avec si ils ne sont pas opérationnels sur la machine cible.

    • Marqué comme réponse Gloops mercredi 21 février 2018 10:12
    • Non marqué comme réponse Gloops jeudi 1 mars 2018 10:43
    mercredi 21 février 2018 10:12
  • Je pense que vous vous faites des nœuds au cerveau pour pas grand-chose.

    DataSet n'a jamais été lié à ODBC, ni même à ADO.NET, qui n'a rien à voir avec ADO (à mort les marketeux), et ADO.NET est votre "un accès .Net".

    Il est tout à fait possible de remplir un DataSet entièrement par code, par la lecture d'un simple fichier CVS, par appel à un WebService SOAP, etc... sans le moindre composant Middleware, et encore moins avec cette antiquité des années 1990 qu'est ODBC : obsolète depuis près de 20 ans.

    Je ne sais pas ce qui vous à fait penser le contraire, mais vous avez dû complètement vous méprendre sur le sujet.

    DataSet n'a aucune adhérence avec aucune technologie de Middleware base de données.

    Mais bon, dégager ODBC, c'est un truc qui aurait dû être fait il y a 20 ans. Je ne vais pas vous indiquez comment continuer à utiliser cette horrible usine à gaz.

    >d'un peu plus près MDAC ne revendique pas de compatibilité avec Windows 10

    ENFIN, qu'il crève ce machin !!!

    >que Microsoft présente pourtant comme la panacée à utiliser de manière universelle.

    où ça ? Dans un article d'il y a 25 ans, face à JDBC ???

    >il faut l'ODBC sur la machine de développement pour pouvoir utiliser l'interface graphique de création de Dataset.

    ABSOLUMENT PAS, vous êtes sur quel version de VS, quel type de projet, quel configuration de projet et connexionString ???

    >Ce que l'ODBC peut poser comme problème, c'est le déploiement.

    Non, ça fait 20 ans que ce machin doit CREVER !!!

    >si on accède aux données par code à l'aide d'un accès .Net.

    Non, en ADO.NET (ou en d'autres Middleware comme Entity Framework ou NHibernate).

    .NET n'a pas d'accès base de données "Natif", il y a des technologies d'accès base de données accessible depuis .NET.

    ADO.NET a toujours été une technologie satellite de .NET, non migrée ou tardivement migrée sur les autres implémentations .NET que l'implémentation M$.

    Le DataAdapter que vous mentionnez est un ajout de ADO.NET 2.0, livrés dans l'implémentation M$ de .NET 2.0 (il y a plus de 16 ans).

    Ce que vous présentez avec DataAdapter est la manière la plus standard d'utiliser ADO.NET depuis plus de 15 ans. Je vous conseille de n'utiliser les classes spécifiques à une source de données, comme PostgreSql, quand dernier recours. Cela permet de choisir le type de source de données de manière totalement dynamique, ADO.NET se chargeant lui-même de trouver et configurer le Middleware d'accès aux données, juste grâce à la magie de la connexionString (Pas comme ces cochonneries de DSN d'ODBC).

    Et si vous êtes masochiste, vous pouvez utiliser des chaines de connexion pour charger ODBC comme Middleware, qui, magie de l'usine à gaz, chargera lui aussi son propre Middleware d'accès (ouais, en plus ODBC, c'est même pas une vraie source de données, c'est qu'une interconnexion à la con, à base de DSN) : MiddlewareCeption.

    Vous avez donc, si j'ai bien compris, juste migré votre code de l'utilisation d'ADO.NET 1.0 à base de cette saleté de DataReader, utilisant une connexion à ODBC (qui n'était pas obligatoire, je le rappelle, ADO.NET pouvait adresser bien des bases de données sans ODBC/MDAC) à l'utilisation d'ADO.NET 2.0 (d'il y a 16 ans) mais en lui collant, inutilement je pense, des dépendances avec la couche d'accès PostgreSql via ADO.NET.

    Ok, juste pour que vous ne soyez pas surpris lors du déploiement, dans votre architecture, vous utilisez le middleware ADO.NET pour PostgreSql, qui n'est pas intégré "de base" dans le framework .NET.

    Il faudra donc ajouter dans votre package d'installation ce middleware. Je vous laisse compulser la documentation de ce middleware pour connaitre la marche a suivre pour une installation de celui-ci dans le déploiement d'une application l'utilisant.

    Je vous rassure, généralement, ce type de middleware s'installe largement plus facilement que cette calamité de MDAC.


    Paul Bacelar, Ex - MVP VC++

    mardi 27 février 2018 18:26
  • Bonjour,

    C'est sous Visual Studio 2017, comment est-ce qu'on configure l'interface graphique pour qu'elle crée un Dataset sans recourir à ODBC ?

    mardi 27 février 2018 22:16
  • J'ai testé avec Visual Studio 2017 pour vérifier s'il n'y avait pas des options par défaut qui pouvaient induire en erreur mais je n'ai rien vu de telles.

    J'ai l'impression qu'on ne parle pas de la même chose.

    Moi,

    - je crée un nouveau projet Winform C#,

    - je demande à ajouter un nouvel élément "DataSet"

    - j'ajoute un DataTable via le Designer de "DataSet" automatiquement ouvert à l'étape précédente

    - j'ajoute une colonne à cette DataTable, que je nomme "test1"

    - J'ajoute un DataGridView à Form1 via de Designer de Formulaire

    - J'ajoute/modifie le code suivant dans Form1.cs :

    namespace Tests
    {
        public partial class Form1 : Form
        {
            DataSet1 m_ds = new DataSet1();
    
            public Form1()
            {
                InitializeComponent();
                m_ds.DataTable1.AddDataTable1Row("TEST");
                dataGridView1.DataSource = m_ds.DataTable1;
            }
        }
    }

    et TADA, j'ai ma grille qui utilise un DataSet qui n'est absolument dépendant de RIEN, et encore moins de cette cochonnerie d'ODBC.

    Si vous avez une dépendance avec ODBC, elle ne vient clairement pas du Dataset mais obligatoirement de votre code ou de la configuration de votre projet.


    Paul Bacelar, Ex - MVP VC++

    mercredi 28 février 2018 15:45
  • Bonjour,

    Je crois que j'ai trouvé l'explication, toute simple.

    Revenons-en aux basiques pour comprendre. Pour créer un Dataset, je fais un clic droit sur le projet, puis je clique "Ajouter, nouveau". Dans la catégorie Données, je choisis DataSet.

    J'arrive sur la surface du concepteur, avec dans l'onglet le titre DataSet1.xsd

    A partir de l'explorateur de serveurs, je trouve la table qui m'intéresse, et je la fais glisser vers la surface du concepteur.

    Etant parti, dans l'explorateur de serveurs, d'une connexion disponible en ODBC, j'ai trouvé dans le code de DataSet1.Designer.cs :

            internal global::System.Data.Odbc.OdbcConnection Connection {
                get {
                    if ((this._connection == null)) {
                        this.InitConnection();
                    }
                    return this._connection;
                }
                set {
                    this._connection = value;
                    if ((this.Adapter.InsertCommand != null)) {
                        this.Adapter.InsertCommand.Connection = value;
                    }
                    if ((this.Adapter.DeleteCommand != null)) {
                        this.Adapter.DeleteCommand.Connection = value;
                    }
                    if ((this.Adapter.UpdateCommand != null)) {
                        this.Adapter.UpdateCommand.Connection = value;
                    }
                    for (int i = 0; (i < this.CommandCollection.Length); i = (i + 1)) {
                        if ((this.CommandCollection[i] != null)) {
                            ((global::System.Data.Odbc.OdbcCommand)(this.CommandCollection[i])).Connection = value;
                        }
                    }
                }
            }


    Pour le cas où je serais tenté de faire la correction à ce niveau, je trouve en tête de fichier l'avertissement :

    // <auto-generated>
    //     Ce code a été généré par un outil.
    //     Version du runtime :4.0.30319.42000
    //
    //     Les modifications apportées à ce fichier peuvent provoquer un comportement incorrect et seront perdues si
    //     le code est régénéré.
    // </auto-generated>

    Si maintenant, lors de la création du DataSet avec l'interface graphique, au lieu de glisser une table depuis une connexion ODBC, je glisse une table depuis une connexion PGSQL, j'obtiens :

            internal global::Devart.Data.PostgreSql.PgSqlConnection Connection {
                get {
                    if ((this._connection == null)) {
                        this.InitConnection();
                    }
                    return this._connection;
                }
                set {
                    this._connection = value;
                    if ((this.Adapter.InsertCommand != null)) {
                        this.Adapter.InsertCommand.Connection = value;
                    }
                    if ((this.Adapter.DeleteCommand != null)) {
                        this.Adapter.DeleteCommand.Connection = value;
                    }
                    if ((this.Adapter.UpdateCommand != null)) {
                        this.Adapter.UpdateCommand.Connection = value;
                    }
                    for (int i = 0; (i < this.CommandCollection.Length); i = (i + 1)) {
                        if ((this.CommandCollection[i] != null)) {
                            ((global::Devart.Data.PostgreSql.PgSqlCommand)(this.CommandCollection[i])).Connection = value;
                        }
                    }
                }
            }

    La réponse à la question était donc :

    faire attention à la connexion choisie dans l'explorateur de serveurs, au cours de l'utilisation de l'interface graphique du concepteur de DataSet de Visual Studio.



    • Marqué comme réponse Gloops jeudi 1 mars 2018 10:43
    • Modifié Gloops jeudi 1 mars 2018 10:46
    jeudi 1 mars 2018 10:42
  • >je trouve la table qui m'intéresse, et je la fais glisser vers la surface du concepteur.

    C'est là que le Designer utilise les spécificités du type de la DataSource pour générer des classes qui seront spécifiques à ce type de DataSource.

    Mais rien ne vous oblige à utiliser ces fonctionnalités.

    Vous pouvez très bien construire votre DataSet "à la main", ou bien, supprimer du code généré, tout ce qui ressemble à une dépendance avec le type spécifique de la DataSource.

    L'usage du Designer est archaïque et, par défaut, colle un max de dépendance malvenue.

    L'utilisation d'outil de génération de DAL (Data Access Layer) comme Entity Framework ou NHibernate rend les choses bien plus souples.


    Paul Bacelar, Ex - MVP VC++

    vendredi 2 mars 2018 16:41
  • Bonjour,

    En effet, on peut aussi tout faire à la main dans un éditeur de texte, et prendre modèle sur les développeurs C qui insèrent leurs clauses header.

    Après tout, à une époque, je faisais de l'assembleur sous DEBUG (après, j'ai quand même trouvé que le macro-assembleur, c'était pratique).

    Mais quand même, quand je fais glisser une table et qu'ensuite avec deux clics de souris ça me fait apparaître les données, c'est là que j'ai envie de dire Tada.

    C'est utile de maîtriser les deux, pour bénéficier de la rapidité de l'interface graphique, et de la souplesse du code écrit à la main.

    vendredi 2 mars 2018 17:00
  • >c'est là que j'ai envie de dire Tada.

    C'est plutôt là que qu'on défonce l'approche SOLID, et en particulier le D pour l'inversion de dépendance.

    Franchement, être tanqué avec un gestionnaire de données obligatoire simplement parce que j'ai utilisé un outil à peine plus récent qu'ODBC ( ;-° ), au lieu d'outils m'offrant bien plus de possibilités et de souplesses, comme Entity Framework ou NHibernate, je trouve cela très dommage.

    Et je parle même pas de la testabilité de machin qui oblige à voir un SGBDR au cul juste pour tester un "click sur un bouton".

    Avoir tout à refaire quand on change de SGBDR juste parce qu'on a voulu gagner 10 minutes (et encore, une fois les outils de plus au niveau d'abstraction comme Entity Framework ou NHibernate maitrisée vous gagnerez bien plus de temps que ces 10 minutes, au combien bien plus), c'est ballot.

    Je ne dis pas qu'il ne faut pas s'en servir, mais il faut connaitre ces grosse limitations et comment arranger le coup avec quelques "Find and Replace".


    Paul Bacelar, Ex - MVP VC++


    vendredi 2 mars 2018 17:16