Pourquoi ma collection de proxy Entity Framework Code First est-elle nulle et pourquoi ne puis-je pas la définir?

J’utilise DBContext et j’ai deux classes dont les propriétés sont toutes virtuelles. Je peux voir dans le débogueur que je reçois un object proxy lorsque j’interroge le contexte. Cependant, une propriété de collection est toujours nulle lorsque j’essaie de l’append. Je pensais que le proxy assurerait l’initialisation de la collecte.

Étant donné que mon object Poco peut être utilisé en dehors de son contexte de données, j’ai ajouté une vérification pour que la collection soit nulle dans le constructeur et la crée si nécessaire:

public class DanceStyle { public DanceStyle() { if (DanceEvents == null) { DanceEvents = new Collection(); } } ... public virtual ICollection DanceEvents { get; set; } } 

Cela fonctionne en dehors du contexte de données, mais si je récupère un object en utilisant une requête, bien que le test soit vrai, j’obtiens l’exception suivante lorsque j’essaie de le définir: ‘Impossible de définir la propriété’ DanceEvents ‘ la collection est déjà définie sur une entité EntityCollection. ‘

Je peux voir que c’est nul et je ne peux pas y append, mais je ne peux pas non plus le définir dans une collection car le proxy dit qu’il est déjà défini. Je ne peux donc pas l’utiliser. Je suis confus.

Voici la classe DanceEvent:

 public class DanceEvent { public DanceEvent() { if (DanceStyles == null) { DanceStyles = new Collection(); } } ... public virtual ICollection DanceStyles { get; set; } } 

J’ai omis les autres propriétés de type valeur du code ci-dessus. Je n’ai aucun autre mappage pour ces classes dans la classe de contexte.

Comme vous l’avez correctement observé dans la réponse à votre propre question, la suppression du mot clé “virtual” des propriétés de la collection permet de résoudre le problème en empêchant Entity Framework de créer un proxy de suivi des modifications. Cependant, ce n’est pas une solution pour beaucoup de gens, car les proxys de suivi des modifications peuvent être très pratiques et peuvent aider à prévenir les problèmes lorsque vous oubliez de détecter les modifications aux bons endroits dans votre code.

Une meilleure approche serait de modifier vos classes POCO, afin qu’elles instancient les propriétés de la collection dans leur accesseur get, plutôt que dans le constructeur. Voici votre classe POCO, modifiée pour permettre la création de proxy de suivi des modifications:

 public class DanceEvent { private ICollection _danceStyles; public virtual ICollection DanceStyles { get { return _danceStyles ?? (_danceStyles = new Collection()); } protected set { _danceStyles = value; } } } 

Dans le code ci-dessus, la propriété de collection n’est plus automatique, mais possède plutôt un champ de sauvegarde. Il est préférable de laisser le setter protégé, empêchant tout code (autre que le proxy) de modifier ultérieurement ces propriétés. Vous remarquerez que le constructeur n’était plus nécessaire et a été supprimé.