Accueil

Utiliser les Metadata avec Entity Framework 5

by Jean-Camille Mercier 30. avril 2013 07:59

Depuis que nous utilisons des ORM (Entity Framework 5 par exemple), nous avons dans nos projets des fichiers générés dans lesquels nous ne pouvons pas faire de modification. Pour palier à cette lacune, le dot Net nous a donné une solution bien connue : les classes partielles. Nous pouvons ainsi continuer à implémenter les classes générées très simplement.

Cependant, il arrive que nous voulions décorer une des propriétés générée par l'ORM avec un attribut custom, un validateur par exemple. Dans ce cas très précis, nous sommes obligé de faire intervenir une classe METADATA qui va fusionner les nouveaux attributs sur les propriétés de notre model. Cette technique possède un formalisme très rigoureux qu'il est important de connaitre.

Prenons l'exemple de cette classe générée :

public partial class AccidentTravail 
{
    public AccidentTravail()
    {
        this.Lesions = new ObservableCollection<Lesion>();
        this.ApresConstructeur();
    }
    
    partial void ApresConstructeur();
    
    ...

    public virtual ObservableCollection<Lesion> Lesions { get; set; }
    
}

[ Vous noterez la présence d'une méthode partielle pour enrichir le constructeur. ]

Pour ajouter un validateur custom sur la collection "Lesions", il faut donc écrire la classe métadata suivante :

[MetadataType(typeof(AccidentTravailMetadata))]
public partial class AccidentTravail
{
    static AccidentTravail()
    {
        // Association manuelle si pas en Dynamic Data
        TypeDescriptor.AddProvider(
          new AssociatedMetadataTypeTypeDescriptionProvider(typeof(AccidentTravail)), 
          typeof(AccidentTravail));
    }

    internal sealed class AccidentTravailMetadata
    {
        // Metadata classes are not meant to be instantiated.
        private AccidentTravailMetadata() { }

        [LesionsValidator]
        public ObservableCollection<Lesion> Lesions;
    }
}

C'est l'attribut "MetadataType" qui va associer cette fameuse classe à notre classe générée. Attention néanmoins : cette attribut ne fonctionne qu'avec les contextes d'objet dynamique tel que WCF, RIA Service ou ASP Net Dynamic Data. Dans la cas où vous consommez vos objet directement depuis l'ORM, il est obligatoire de faire l'association en manuel au moyen de la méthode "TypeDescriptor.AddProvider" que j'ai simplement placé dans le constructeur static pour l'appeler qu'une seule fois.

 Pour finir vous pouvez désactiver le warning 649 (Field 'field' is never assigned to, and will always have its default value 'value') en plaçant en tête et pied de fichier :

#pragma warning disable 0649
...
#pragma warning restore 0649