En travaillant sur une application Web ASP.NET MVC dans laquelle j’utilise Entity Framework 4 Code First, j’ai eu l’erreur suivante : «A circular reference was detected while serializing an object of type… » lorsque j’ai essayé de retourner une classe Entité au client comme un document JSON.
À première vue, il semblerait qu’il y ait une référence circulaire dans ma hiérarchie d’objets qui n’est pas prise en charge par le sérialiseur JSON.
En essayant de procéder au débogage de la procédure, je me suis rendu compte que le problème n’était pas au niveau de mon code, mais plutôt au niveau de la classe qui s’occupe de la sérialisation.
Quelle est donc la cause de cette erreur :
Pour les tables ayant des relations, l’utilitaire de mappage objet relationnel, génère des propriétés de référence dans chaque entité.
Prenons par exemple le schéma suivant de ma base de données :
Pour la table Liste_produit, L’objet généré aura une propriété Facture. Cependant, pour la table Facture, l’objet généré aura également une propriété Liste_produit. Conséquence : l’objet facture est lié à l’objet Liste_produit et vice-versa.
Ce scénario permet bien évidemment de bénéficier de beaucoup plus d’options lors du traitement de ces entités, mais crée cependant une ambiguïté pour le sérialiseur JSON lors de l’opération de sérialisation. D’où la génération de cette erreur.
Comment résoudre cela ?
Pour résoudre ce type de problème, nous pouvons utiliser deux solutions.
La première solution qui est plutôt simple est de marquer la relation comme une propriété interne.
Perso, je préfère ne pas utiliser cette méthode, car elle m’oblige à modifier mon EDM (Entity Data Model).
La seconde solution, qui est celle pour laquelle j’ai opté, consiste en l’utilisation d’un autre ViewModel en lieu et place de celui généré automatiquement par l’utilitaire de mappage objet/relationnel (ORM).
Cette approche est plus élégante dans la mesure ou elle permettra de sélectionner uniquement les données dont nous avons besoin et sérialiser uniquement celles qui nous intéressent. La conséquence directe est la réduction de la taille des données qui seront retournées dans notre vue et une amélioration de performance de notre application.
Pour utiliser cette méthode, nous devons :
– Dans un premier temps, créer une nouvelle classe qui contiendra uniquement les propriétés dont nous avons besoin.
public partial class ProduitL
{
public short Id_produit
{
get;
set;
}
public string Libelle_produit
{
get;
set;
}
public string Conditionnement
{
get;
set;
}
public int Quantite
{
get;
set;
}
public decimal Prix
{
get;
set;
}
}
Nous allons ensuite modifier la méthode d’action de notre contrôleur comme suit :
public JsonResult Facture(short id)
{
var results = from lp in db.Liste_produit
where lp.Id_facture == id
select new ProduitL
{
Id_produit = lp.Id_produit,
Libelle_produit = lp.produit.Libelle_ produit,
Conditionnement = lp. produit.Conditionnement,
Quantite = lp.Quantite,
Prix = lp.Prix
};
return Json(results);
}
ET voilà , à l’exécution de notre application, nous n’aurons plus cette erreur qui peut s’avérer désorientant pour certains.