avril
2011
Et hop, un jour de perdu sur ce projet. La raison : le trinome EF – POCO – et un constructeur dans un objet POCO.
Pour resituer le contexte, nous réalisons une application qui, entre autre, parse des fichier, et normalise les données contenues.
Ces données sont manipulée par un ORM (object-relational mapping) : Entity Framework 4, et ce en mode POCO (Plain Old CLR Object).
Ce qui signifie, que nous avons totalement la main sur le code des classes manipulées, et Entity Framework est responsable de la gestion des instances de ces classes, avec le moteur de Bdd.
Enfin, pour que le contexte soit complet, j’ajoute que la gestion de l’état des instances est réalisé par la mise en virtual des propriétés des objets (Du coup, EF crée un proxy sur mon objet pour gérer son état).
Ces classes (internal à l’assembly) implémentent des interfaces (publiques), et sont instanciées par une fabrique.
Les assemblies consommateurs n’ont donc ni conscience de l’implémentation réelle, ni de la façon dont sont instanciées les classes. (bref un couplage faible).
Le problème : J’ai une classe Voiture qui contient une propriété Moteur. Ce dernier contient les propriétés Batterie , Compresseur de Climatisation. (tous ces types sont des types références, donc des classes)
Pour récapituler :
public class Voiture { public Moteur MonMoteur { get; set; } } public class Moteur { public Moteur() { this.MonCompresseurClim = new CompresseurClim(); this.MaBatterie = new Batterie(); } public CompresseurClim MonCompresseurClim { get; set; } public Batterie MaBatterie { get; set; } } public class CompresseurClim { // … } public class Batterie { //… }
Lors de l’instanciation de la voiture, la valeur du moteur est instanciée par le constructeyr (pour éviter les null, les consommateur de ces classes les manipulent à travers leurs interfaces qui ne permettent pas les setter.), lors de l’instanciation du dit moteur, les valeurs de Batterie, et CompresseurClim sont instanciées.
Ceci est réalisé dans les constructeurs respectifs (classes partielles), bien entendu.
Le problème : lors de la récupération de la voiture depuis la base de données (via EF),
le moteur est bien récupéré en Lazy load, mais
la batterie et le compresseur ne correspondent pas à la valeur en base de données.
Pire : EF est incapable de récupérer le valeur correcte du moteur !
En lieu et place, les propriétés sont instanciés avec les objets par défaut.
Pour diagnostiquer j’ai :
– Mis en place le SQL Server Profiler (pour visualiser le sql d’EF,
– remonté le modèle EF dans un autre projet, en remontant par passe successive le T4 POCO, puis les classes partielles, les interfaces,
je me suis rendu compte que le problème apparaissait dans cette appli de test, juste après l’insertion du code des classes partielles.
Puis, en supprimant le contenu du constructeur du moteur (qui initialise la batterie et le compresseur de clim avec les valeurs par défaut), EF ne plante plus et récupère correctement les valeurs…
J’en déduis que, lors de la création du proxy EF sur mon objet, il doit analyser le constructeur, repiquer mon code et l’exécuter après ses requêtes en db… du coup, mes valeurs sont toujours à leur état par défaut !
Attention donc, aux constructeurs dans des classes EF – mode POCO !!!
PS : si quelqu’un sait ce qui se passe précisément…
Re-PS : les classes ne correspondent pas à la réalité (si si si )