none
Enums en lien avec une table de contrainte d'intégrité, definir la valeur 0 ? RRS feed

  • Question

  • Bonsoir,

    Référence: Les enums doivent avoir la valeur zéro

    Prenons pour exemple la civilité, je suis plutot partant de demarrer les valeur a 1. Pour moi la valeur 0 c'est rien ou non définit ou encore état initial (ce qui est vrai pour int, enum, etc).

    Déja, faites vous démarrer vos enums à 0 ou à 1 ?

    Voici ensuite un exemple concret:

    En bdd j'ai une table qui sera cible d'un Foreign key sur les valeurs (par ex sur une table client):

     1 Mme

     2 Mlle

     3 M.

    Dans le code j'ai un enum correspondant (je transtype apres lecture en bdd ou avant ecriture bdd)

     enum Civilité { Mme = 1, Mlle, M. }

     

    Doit-on définir une valeur pour le zéro dans cet enum (init par defaut de l'enum) ?

    Sachant que si par malheur mon enum vaut 0, j'aurait une exception lors de l'insert en bdd.

    Avis, avisés bienvenue sur le sujet !

     


    Sinn'
    mardi 27 avril 2010 21:27

Réponses

  • Bonjour Sinner73fr,

    Si tu n'aime pas le 0 comme valeur par défaut, tu peux jouer avec l'attribut DefaultValue.

    C'est un attribut qui peut se mettre sur une prorpriété pour lui donner une valeur par défaut :

    class TaClasse
    {
    [DefaultValue(Civilite.Mme)]
    public Civilite TaProprieteCivilite {get;set;}
    }

    Voici la documentation sur le sujet :

    http://msdn.microsoft.com/fr-fr/library/system.componentmodel.defaultvalueattribute.aspx

     

    PS: attention : il faut éviter d'utiliser les caractères spéciaux et accents dans ton code "Civilité" "M." cela risque de te poser des soucis par la suite.


    Jérémy Jeanson MCP http://blogs.codes-sources.com/JeremyJeanson/ (French or English Spoken)
    mercredi 28 avril 2010 08:32
  • Bonjour,

    La valeur 0 pour énumération est recommandée mais pas obligatoire :

    http://msdn.microsoft.com/en-us/library/ms182149(VS.80).aspx

    Par défaut, les variables de type énumération sont initialisées à 0 (et donc avec une valeur incorrecte si une valeur 0 n'a pas été défini pour l'énumération). Je vous recommande fortement de définir la valeur 0 pour "M" par exemple et d'autoriser cette valeur par votre SGBD.

    Au passage, les énumérations sont conçues pour ne pas changer au fil du temps (ce sont des constantes). Or, vous les mettez en ligne dans votre SGBD, ce qui veut dire qu'il est possible d'ajouter/modifier/supprimer vos civilités. Dans ce cas, vous risquez de devoir modifier votre civilité (recompilation -> re-livraison). Préférez dans ce cas, l'utilisation d'objets ou d'un DataTable qui est automatiquement alimenté une seule fois au démarrage du programme.

    Cordialement


    Gilles TOURREAU - MVP C# - Architecte .NET/Consultant/Formateur
    jeudi 29 avril 2010 06:59
    Modérateur
  • Bonjour,

    Il serait presque préférable de laisser les champs civilité des tables personnes et adresses en tinyint dans ce cas ? Mais ce qui m'ennuie alors c'est qu'avec de multiples appli tiers (batch, site web, autre) accédant aux meme sgbd, on déporte l'intégrité de la définition des civilités dans les appli tierces.

    Il y a donc contradiction avec ce que vous voulez faire en faisant une énumération... (Vous déportez l'intégrité de la définition des civilités dans votre application).

    Normalement, soit vous utilisez une table pour représentez vos civilités, dans ce cas au niveau de (ou des) application vous utilisez cette table sans utiliser d'énumération (l'affichage des civilités se fait dans alors dans des contrôles de "contenu dynamique" tel que des listes, tables, combo...). C'est donc le SGBD (et l'utilisateur plus généralement) qui "donne" de la sémantique aux civilités.

    Soit vous utilisez "un code" (le tinyint que vous évoquez est un très bon exemple) dans votre SGBD (avec une contrainte CK). C'est aux applications dans ce cas de traiter ces différentes valeurs (via une énumération par exemple) et de leur donner de la sémantique.

    J'ai pris l'exemple de la civilité, mais, c'est aussi le cas pour un moyen de paiement ou un mode livraison, qui pourront évoluer et s'étoffer au fil du temps. Il est vrai que dans ce cas il faut modifier BDD et code source en meme temps. Mais avec un projet (dll) de constante a part qui contient les enum, c'est trés facile. Et dans ce cas, une seul dll a redeployer, ce qui est bien peu de contrainte !

    On tient généralement ce discours au début du projet. Durant l'évolution et la maintenance du logiciel c'est moins le cas... Surtout quand vous avez un DBA ou un administrateur réseau qui font la guerre avec l'équipe de développement...

    Cordialement


    Gilles TOURREAU - MVP C# - Architecte .NET/Consultant/Formateur
    vendredi 30 avril 2010 06:33
    Modérateur

Toutes les réponses

  • Bonjour Sinner73fr,

    Si tu n'aime pas le 0 comme valeur par défaut, tu peux jouer avec l'attribut DefaultValue.

    C'est un attribut qui peut se mettre sur une prorpriété pour lui donner une valeur par défaut :

    class TaClasse
    {
    [DefaultValue(Civilite.Mme)]
    public Civilite TaProprieteCivilite {get;set;}
    }

    Voici la documentation sur le sujet :

    http://msdn.microsoft.com/fr-fr/library/system.componentmodel.defaultvalueattribute.aspx

     

    PS: attention : il faut éviter d'utiliser les caractères spéciaux et accents dans ton code "Civilité" "M." cela risque de te poser des soucis par la suite.


    Jérémy Jeanson MCP http://blogs.codes-sources.com/JeremyJeanson/ (French or English Spoken)
    mercredi 28 avril 2010 08:32
  • Bonjour,

    Pourquoi ne pas utiliser un type nullable ?

    Une valeur nulle signifie non renseigné. 

    Les bases de données prennent en charge les types nullables pourquoi pas notre code...

     

    mercredi 28 avril 2010 08:35
  • Bonjour Atmeitsatme,

    Je crois avoir compris que la base de données n'accepterait pas de valeur 0 ou null. Pour un type Nullable c'est donc compromis.


    Jérémy Jeanson MCP http://blogs.codes-sources.com/JeremyJeanson/ (French or English Spoken)
    mercredi 28 avril 2010 08:41
  • Bonjour,

    La valeur 0 pour énumération est recommandée mais pas obligatoire :

    http://msdn.microsoft.com/en-us/library/ms182149(VS.80).aspx

    Par défaut, les variables de type énumération sont initialisées à 0 (et donc avec une valeur incorrecte si une valeur 0 n'a pas été défini pour l'énumération). Je vous recommande fortement de définir la valeur 0 pour "M" par exemple et d'autoriser cette valeur par votre SGBD.

    Au passage, les énumérations sont conçues pour ne pas changer au fil du temps (ce sont des constantes). Or, vous les mettez en ligne dans votre SGBD, ce qui veut dire qu'il est possible d'ajouter/modifier/supprimer vos civilités. Dans ce cas, vous risquez de devoir modifier votre civilité (recompilation -> re-livraison). Préférez dans ce cas, l'utilisation d'objets ou d'un DataTable qui est automatiquement alimenté une seule fois au démarrage du programme.

    Cordialement


    Gilles TOURREAU - MVP C# - Architecte .NET/Consultant/Formateur
    jeudi 29 avril 2010 06:59
    Modérateur
  • Merci pour ces réponses.

    Concernant l'enum à 0, je suis un peu bloqué car je pars d'un sgbd existant, et ma table civilité (déjà existante) démarre a 1.

    Finalement le problème est d'avoir d'une part une table Civilite, qui est une FK depuis une autre table personnes ou adresses , et d'autre part d'utiliser un enum associé qui redefinit a l'identique le contenu de la table (enum = clarté du code).

    Il serait presque préférable de laisser les champs civilité des tables personnes et adresses en tinyint dans ce cas ? Mais ce qui m'ennuie alors c'est qu'avec de multiples appli tiers (batch, site web, autre) accédant aux meme sgbd, on déporte l'intégrité de la définition des civilités dans les appli tierces.

    Dans mon option, la contrainte est sur le sgbd, et donc garantit l'unicité des valeur en bdd. Si on insere 0 ou autre autre valeur que 1, 2, 3 on aura une erreur sql independemment de l'appli utilisée, y compris SSMS, erreur a gerer, mais qui insere en bdd sans gestion d'erreur ?

    J'ai pris l'exemple de la civilité, mais, c'est aussi le cas pour un moyen de paiement ou un mode livraison, qui pourront évoluer et s'étoffer au fil du temps. Il est vrai que dans ce cas il faut modifier BDD et code source en meme temps. Mais avec un projet (dll) de constante a part qui contient les enum, c'est trés facile. Et dans ce cas, une seul dll a redeployer, ce qui est bien peu de contrainte !

     

    Cordialement,

    Sinn'


    Sinn'
    jeudi 29 avril 2010 13:05
  • Bonjour,

    Il serait presque préférable de laisser les champs civilité des tables personnes et adresses en tinyint dans ce cas ? Mais ce qui m'ennuie alors c'est qu'avec de multiples appli tiers (batch, site web, autre) accédant aux meme sgbd, on déporte l'intégrité de la définition des civilités dans les appli tierces.

    Il y a donc contradiction avec ce que vous voulez faire en faisant une énumération... (Vous déportez l'intégrité de la définition des civilités dans votre application).

    Normalement, soit vous utilisez une table pour représentez vos civilités, dans ce cas au niveau de (ou des) application vous utilisez cette table sans utiliser d'énumération (l'affichage des civilités se fait dans alors dans des contrôles de "contenu dynamique" tel que des listes, tables, combo...). C'est donc le SGBD (et l'utilisateur plus généralement) qui "donne" de la sémantique aux civilités.

    Soit vous utilisez "un code" (le tinyint que vous évoquez est un très bon exemple) dans votre SGBD (avec une contrainte CK). C'est aux applications dans ce cas de traiter ces différentes valeurs (via une énumération par exemple) et de leur donner de la sémantique.

    J'ai pris l'exemple de la civilité, mais, c'est aussi le cas pour un moyen de paiement ou un mode livraison, qui pourront évoluer et s'étoffer au fil du temps. Il est vrai que dans ce cas il faut modifier BDD et code source en meme temps. Mais avec un projet (dll) de constante a part qui contient les enum, c'est trés facile. Et dans ce cas, une seul dll a redeployer, ce qui est bien peu de contrainte !

    On tient généralement ce discours au début du projet. Durant l'évolution et la maintenance du logiciel c'est moins le cas... Surtout quand vous avez un DBA ou un administrateur réseau qui font la guerre avec l'équipe de développement...

    Cordialement


    Gilles TOURREAU - MVP C# - Architecte .NET/Consultant/Formateur
    vendredi 30 avril 2010 06:33
    Modérateur
  • Bonjour,

    Il serait presque préférable de laisser les champs civilité des tables personnes et adresses en tinyint dans ce cas ? Mais ce qui m'ennuie alors c'est qu'avec de multiples appli tiers (batch, site web, autre) accédant aux meme sgbd, on déporte l'intégrité de la définition des civilités dans les appli tierces.

    Il y a donc contradiction avec ce que vous voulez faire en faisant une énumération... (Vous déportez l'intégrité de la définition des civilités dans votre application).

    Normalement, soit vous utilisez une table pour représentez vos civilités, dans ce cas au niveau de (ou des) application vous utilisez cette table sans utiliser d'énumération (l'affichage des civilités se fait dans alors dans des contrôles de "contenu dynamique" tel que des listes, tables, combo...). C'est donc le SGBD (et l'utilisateur plus généralement) qui "donne" de la sémantique aux civilités.

    Soit vous utilisez "un code" (le tinyint que vous évoquez est un très bon exemple) dans votre SGBD (avec une contrainte CK). C'est aux applications dans ce cas de traiter ces différentes valeurs (via une énumération par exemple) et de leur donner de la sémantique.

    J'ai pris l'exemple de la civilité, mais, c'est aussi le cas pour un moyen de paiement ou un mode livraison, qui pourront évoluer et s'étoffer au fil du temps. Il est vrai que dans ce cas il faut modifier BDD et code source en meme temps. Mais avec un projet (dll) de constante a part qui contient les enum, c'est trés facile. Et dans ce cas, une seul dll a redeployer, ce qui est bien peu de contrainte !

    On tient généralement ce discours au début du projet. Durant l'évolution et la maintenance du logiciel c'est moins le cas... Surtout quand vous avez un DBA ou un administrateur réseau qui font la guerre avec l'équipe de développement...

    Cordialement


    Gilles TOURREAU - MVP C# - Architecte .NET/Consultant/Formateur

    Bonjour tout le monde,

    Je suis à 200% en accord avec le témoignage de Gilles....

    De par mon expérience des contacts "DBA / IT". Un développeur doit faire abstraction de ses "envies". Il doit chercher à cadre avec la logique des DBA. Dans mon cas je n'ai jamais eu d'énumérations "en dur". Le code a toujours été managé par la donnée afin d'éviter les recompilations inutiles juste pour changer quelques paramètres.

    Et tout cela doit se faire au début de projet, si non on risque de se faire taper sur les doigts et d'être contre productif :(


    Jérémy Jeanson MCP http://blogs.codes-sources.com/JeremyJeanson/ (French or English Spoken)
    vendredi 30 avril 2010 14:09