Publié samedi 25 octobre 2008 14:56 par Luke77

MappingAttribute

Après 4 mois d'abstinence, je reviens avec un post plutôt simple, voir très simple, mais qui va servir d'introduction à une série plus longue sur du code que j'ai recement écrit pour mon client unique et favoris. J'ai donc eu l'occasion de mettre en place un un mini framework. Pour la petite histoire, mes articles précédents font partie de ce framework, à savoir principalement : les singletons (sujet qui fait grand débat), mon propre cache et la configuration (dont l'explication reste inachevée mais je n'avais pas l'impression que cela captivait énormément les rares personnes qui venaient se perdre sur ce blog).

Mais revenons à nos moutons ; une des fonctions de ce mini framework est de gérer les entités, leurs chargement depuis la base de données, et le mapping entre ces entitées et le DataReader résultant de l'exécution d'une procédure stockée. Dans le service auquel j'appartiens, la version actuelle du code faisait un mapping écrit à la main par les developpeurs :

  1: monObjet.MaPropriété1 = (MonType)dataReader["MaColonne1"];
  2: monObjet.MaPropriété2 = (MonType1)dataReader["MaColonne2"];
  3: monObjet.MaPropriété3 = (MonType2)dataReader["MaColonne3"];
  4: monObjet.MaPropriété4 = dataReader["MaColonne4"] as MonType4;
  5: monObjet.MaPropriété5 = (MonType5)dataReader["MaColonne5"];

Etant un gros feignant, je voulais quelque chose de moins fastidieux, plus sûr, mais qui ne pénalise pas non plus la performance. Qui plus est, j'avais en tête un système permettant de ne loader que partiellement les objets, il me fallait donc que le code précédent prenne aussi en compte la possibilité que la colonne ne soit pas présente dans le DataReader (par exemple je veux une liste de personne pour afficher leur nom et prénom, cela ne sert donc à rien de récupérer leur sexe ou date de naissance). La génération avec des outils tels que CodeSmith aurait certainement pu faire l'affaire mais je n'en suis pas un grand fan, et c'est aussi beaucoup moins marrant que de coder. C'est pourquoi je me suis mis à l'écrire d'un mapper.

Je me suis fortement inspiré du code de Michel Perfetti qui avait fait un peu la même chose. La différence entre son code et le mien, c'est que Michel se basait sur l'index des colonnes pour effectuer son mapping, or cela n'était pas possible dans mon cas, puisque cet ordre n'était pas prédéfini à l'avance, le nombre de colonnes changeant à chaque requête.

 

J'ai donc commencer par le commencement, créer mon propre attribut de mapping qui me servira à faire le lien entre ma variable de classe ou bien une propriétée de ma classe et la colonne de mon DataReader. Cet attribut devait avoir comme propriétés exposées :

  • ColumnName : le nom de la colonne dans le DataReader
  • BitFieldIndex : une puissance de 2 permettant de savoir le membre est chargé (pour le cas d'un chargement partiel)

Pour résumé à quoi sert ce BitFieldIndex, chaque champs possède une puissance de 2 comme index : 1, 2, 4, 8,16... Au sein de l'entité, une variable permet de savoir quels champs sont chargés ou non grâce à une combinaison de ces puissances. Par exemple si cette variable vaut 11, alors cela signifie que les champs d'index 1, 2 et 8 sont chargés. L'appel au un champ d'index 4 déclenchera dans ce cas un reload complet de l'objet.

 

Sans plus attendre et pour conclure, le code au combien compliqué de cet attribut suivi de son utilisation dans une autre classe :

  1:     [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
  2:     public class MappingAttribute : Attribute
  3:     {
  4:         private string _columnName;
  5:         private ulong _bitFieldIndex;
  6:         public MappingAttribute()
  7:         {
  8:         }
  9:         public string ColumnName
 10:         {
 11:             get { return _columnName; }
 12:             set { _columnName = value; }
 13:         }
 14:         public ulong BitFieldIndex
 15:         {
 16:             get { return _bitFieldIndex; }
 17:             set { _bitFieldIndex = value; }
 18:         }
 19:     }
 20: 
  1:     public class News : Entity<int>
  2:     {
  3:         #region Mapped Fields
  4: 
  5:         private enum MF
  6:         {
  7:             Id = 1,
  8:             Name = 2,
  9:             Content = 4,
 10:             CreationDate = 8,
 11:             ModificationDate = 16
 12:         }
 13: 
 14:         #endregion
 15: 
 16:         #region Private Members
 17: 
 18:         [MappingAttribute(ColumnName = "NewsId", BitFieldIndex = (ulong)MF.Id)]
 19:         private int _id;
 20: 
 21:         [MappingAttribute(ColumnName = "Name", BitFieldIndex = (ulong)MF.Name)]
 22:         private string _name;
 23: 
 24:         [MappingAttribute(ColumnName = "Content", BitFieldIndex = (ulong)MF.Content)]
 25:         private string _content;
 26: 
 27:         [MappingAttribute(ColumnName = "CreationDate", BitFieldIndex = (ulong)MF.CreationDate)]
 28:         private DateTime _creationDate;
 29: 
 30:         [MappingAttribute(ColumnName = "ModificationDate", BitFieldIndex = (ulong)MF.ModificationDate)]
 31:         private DateTime _modificationDate;
 32: 
 33:         #endregion
 34: 
 35:     }
 36: 

 

Petite dédicace à bibi : Ne pars pas !
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :

# re: MappingAttribute @ samedi 25 octobre 2008 15:01

Je reviendrai!

dubrow

# re: MappingAttribute @ samedi 25 octobre 2008 20:26

Heu moi j'utilise votre système de config en db :p

teddyalbina

# re: MappingAttribute @ mardi 28 octobre 2008 21:55

Salut teddyalbina,

tu serais interressé par la suite de la configuration ? Je peux faire d'autres articles là dessus.

Luke77

# re: MappingAttribute @ vendredi 27 novembre 2009 23:51

Holalalal désolé pour le temps de réponse mais oui je suis fortement interessé :)

teddyalbina


Les 10 derniers blogs postés

- Comment mapper une vue SQL sur une collection de complex type? par Matthieu MEZIL le il y a 5 heures et 9 minutes

- SQL Server : Query Notification ou comment être notifié de modifications de données côté application (SqlDependency) par SQL Server vu par Christian Robert le il y a 11 heures et 9 minutes

- [WF4] Un Binding Activity/ActivityDesigner qui passe mal? par Blog de Jérémy Jeanson le il y a 12 heures et 32 minutes

- MyTIC – SharePoint 2010 : déjà un mythe Microsoft ? par Le Blog (Vert) d'Arnaud JUND le il y a 17 heures et 20 minutes

- TechDays 2010 Genève : Retrouvez-moi pour une session sur la Haute disponibilité et le ScaleOut avec SQL Server par SQL Server vu par Christian Robert le 03-18-2010, 15:45

- [MIX10] Keynote deuxième journée – Internet Explorer 9, Html5, Visual Studio 2010, OData par Atteint de JavaScriptite Aiguë [Cyril Durand] le 03-17-2010, 19:40

- Certifications beta .NET 4 par Kévin Gosse le 03-17-2010, 19:33

- [Mix 2010] – Microsoft Translator Technology Preview V2 par RedoBlog - The .NET Gentleman !!! le 03-17-2010, 18:53

- Lancement en Preview de Cyclone lors des TechDays 2010! par Blog de Frédéric Queudret le 03-17-2010, 16:30

- [WP7] Je ne veux pas d’un nouvel iPhone par Le blog de FremyCompany le 03-17-2010, 13:11