Accueil

DbContext : ObjectMaterialized

by Jean-Camille Mercier 13. mai 2013 22:51

Dans le cas de POCO générés depuis une base de donnée grâce à Entity Framework 5. Il est possible de customiser chaque accesseur des objets pour qu'ils lèvent l'événement "NotifyPropertyChanged" et ainsi utiliser au mieux les mécanismes de binding de WPF. Cependant, je me suis rendu compte que ces événements sont aussi appelés, lorsque l'entité est chargée depuis la base de données. Pour un DateTime par exemple, la valeur par défaut étant 1/1/0001, un "Notify" est levé quand la valeur stockée en BDD est affectée à l'objet.

Pour empêcher ces événements "parasites" j'ai d'abord pensé à vérifier l'état de l'objet avec le state "Detached" par exemple, mais les POCO ne connaissent ni leur état, ni le DbContext qui les charge ce qui a mon sens est logique. On va donc appliquer le mécanisme dans la bon sens à savoir : le DbContext va donner l'information à nos POCO qu'ils sont fini de charger. Pour cela il existe l'événement "ObjectMaterialized" sur lequel on doit s'inscrire ainsi :

partial void ApresConstructeur()
{
    ((IObjectContextAdapter)this).ObjectContext.ObjectMaterialized += OnEntityMaterialized;
}

MSDN : Se produit lorsqu'un nouvel objet d'entité est créé à partir des données de la source de données dans le cadre d'une requête ou d'une opération de chargement.

On peut alors renseigner une propriété de nos POCO indiquant qu'ils sont bien chargés : 

// <summary>
// Lorsque l'entité a fini de se charger en bdd, on la maque IsMaterialized
// Ainsi la validation et les propertiesChanged peuvent être déclenchés
// </summary>
private void OnEntityMaterialized(object sender, ObjectMaterializedEventArgs e)
{
    var entity = e.Entity as BaseEntitie;
    if (entity != null)
        entity.IsMaterialized = true;
}

Attention toute fois à bien lever les événements sur les POCO qui ne viennent pas de la BDD, ceux que l'on instancie nous même. Pour cela je test en plus si la clef primaire de mon objet est à 0 ce qui indique que ce n'est pas une entité qui vient de la BDD :

private bool CanRaiseEvent()
{
    return this.IsMaterialized || this.Id == 0;
}

Reste plus qu'a vérifier cette méthode avant de faire le Raise des notify !