1

I'm using MVC5 and Visual Studio 2013 with entity framework. Basic problem is when we have a many-to-many relationships like this:

public class Person
{
    public int ID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public ICollection<Group> Groups { get; set; }

    public Patient()
    {
        Groups = new HashSet<Group>();
    }
}
public class Group
{
    public Guid ID { get; set; }
    public string Name { get; set; }

    public ICollection<Person> People{ get; set; }

    public Group()
    {
        People = new HashSet<Person>();
    }
}

and we want to get the JSON representation for a record like this

 Person person = db.People.Include(x => x.Groups).Where(i => i.ID == id).Single();
string json=JsonConvert.SerializeObject(person);

the JsonConvert throws a circular reference exception.

This SO question has an easy solution by configuring it to ignore circular reference exceptions:

var serializerSettings = new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.Objects };
string json=JsonConvert.SerializeObject(person,serializerSettings);

My question is this: is this still the best way to deal with this situation? Those SO answers are now very old, and this seems like a very common situation. I've updated everything I can think of to update in my solution, but I still get the exception unless I do the extra configuration step.

Also, are there side effects to setting PreserveReferencesHandling = PreserveReferencesHandling.Objects? Is there any reason ever not do this?

Community
  • 1
  • 1
Matthew
  • 4,149
  • 2
  • 26
  • 53

3 Answers3

0

using datamembers is a better solution I think. Here you can chose what to serialize and what not.

Not adding attributes to the unwanted/circular references solves the problem of the circular serialization.

http://www.newtonsoft.com/json/help/html/DataContractAndDataMember.htm

RoteS
  • 1,405
  • 13
  • 10
0

Another way is to avoid eager loading, by removing include extension method from your statement. Or create another custom class for your dependent object and use projection using select(x => new CustomClass {PropertyOne = p.PropertyOne})

Kopadze
  • 31
  • 4
0

You just need to add [ScriptIgnore(ApplyToOverrides = true)] into your text template (.tt) file (part of the EF data model).

Here a portion of my text template before

#>
<#=codeStringGenerator.NavigationProperty(navigationProperty)#>
<#

Once I inserted the code the line above the codeStringGenerator my classes auto generated and looked like this:

[ScriptIgnore(ApplyToOverrides = true)]
public virtual ICollection<Currency> Currencies { get; set; }

I also needed to modify the UsingDirectives function to insert "using System.Web.Script.Serialization;"