olabi
olabi

Reputation: 59

A circular reference was detected while serializing entities with one to many relationship

How to solve one to many relational issue in asp.net?

I have Topic which contain many playlists.

My code:

public class Topic
{
    public int Id { get; set; }
    public String Name { get; set; }
    public String Image { get; set; }
    --->  public virtual List<Playlist> Playlist { get; set; }
}

and

public class Playlist
{
    public int Id { get; set; }
    public String Title { get; set; }
    public int TopicId { get; set; }
    ---> public virtual Topic Topic { get; set; }
}

My controller function

[Route("data/binding/search")] 
public JsonResult Search()
{
    var search = Request["term"];
    var result=  from m in _context.Topics where m.Name.Contains(search) select m;
    return Json(result, JsonRequestBehavior.AllowGet);
}

When I debug my code I will see an infinite data because Topics will call playlist then playlist will call Topics , again the last called Topic will recall playlist and etc ... !

In general when I just use this relation to print my data in view I got no error and ASP.NET MVC 5 handle the problem .

The problem happens when I tried to print the data as Json I got

enter image description here

Is there any way to prevent an infinite data loop in JSON? I only need the first time of data without call of reference again and again

Upvotes: 1

Views: 825

Answers (1)

Shyju
Shyju

Reputation: 218722

You are getting the error because your entity classes has circular property references.

To resolve the issue, you should do a projection in your LINQ query to get only the data needed (Topic entity data).

Here is how you project it to an anonymous object with Id, Name and Image properties.

public JsonResult Search(string term)
{
    var result = _context.Topics
                         .Where(a => a.Name.Contains(term))
                         .Select(x => new
                                          {
                                               Id = x.Id,
                                               Name = x.Name,
                                               Image = x.Image 
                                });
    return Json(result, JsonRequestBehavior.AllowGet);
}

If you have a view model to represent the Topic entity data, you can use that in the projection part instead of the anonymous object

public class TopicVm
{
    public int Id { set;get;}
    public string Name { set;get;}
    public string Image { set;get;}
}
public JsonResult Search(string term)
{
    var result = _context.Topics
                         .Where(a => a.Name.Contains(term))
                         .Select(x => new TopicVm
                                          {
                                               Id = x.Id,
                                               Name = x.Name,
                                               Image = x.Image 
                                          });
    return Json(result, JsonRequestBehavior.AllowGet);
}

If you want to include the Playlist property data as well, you can do that in your projection part.

public JsonResult Search(string term)
{
    var result = _context.Topics
                         .Where(a => a.Name.Contains(term))
                         .Select(x => new
                                          {
                                               Id = x.Id,
                                               Name = x.Name,
                                               Image = x.Image,
                                               Playlist = x.Playlist
                                                           .Select(p=>new
                                                            {
                                                              Id = p.Id,
                                                              Title = p.Title
                                                            })
                                });
    return Json(result, JsonRequestBehavior.AllowGet);
}

Upvotes: 3

Related Questions