Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

225
Views
How can I avoid circular reference errors when serializing EF Core results?

I have the following entity models set up in my EF Core project:

public class ForumPost
{
    [Key]
    public int Id { get; set; }
    public string Title { get; set; }
    // ...some other properties
    public List<Tag> Tags { get; set; }
}

public class Tag
{
    [Key]
    public string Name { get; set; }
    public string Description { get; set; }
    // ...some other properties
    public List<ForumPost> Posts { get; set; }
}

So I have a many to many relationship between posts and tags. I have no relationship configuration in my OnModelCreating.

My context is setup as follows:

public class ForumsContext : DbContext
{
    public DbSet<ForumPost> Posts { get; set; }
    public DbSet<Tag> Tags { get; set; }
}

When I query my ForumsContext as follows:

 var posts = await context.Posts.Include(p => p.Tags).ToListAsync();

EF automatically populates the Posts field for each of the Tag objects in each of the ForumPost objects in posts. I cannot figure out why this is happening and if I was to serialize the posts list above to JSON it would throw an exception due to the object cycle (Post->Tags->Posts->Post).

Why are the tag's post lists being populated? How can I tell EF to not populate this list.

over 4 years ago · Santiago Trujillo
2 answers
Answer question

0

That's just how Entity Framework works. The Include call populates the navigation property on both sides of the relationship.

Entity Framework conventions dictate that you must have navigation properties on both ends of a many-to-many relationship.

It does not appear to be possible to only have one navigation property using the fluent API, either. The code below does not work, and in asking whether there is a way to avoid defining the property for one of the entities, in this thread the team answered with "Not yet".

modelBuilder.Entity<ForumPost>().HasMany<Tag>(post => post.Tags).WithMany();

JSON object cycles

As for object cycle errors when serializing to JSON, these can be handled or ignored in .NET 5 or later.

This article goes into more detail on the issue, and shows a solution for NewtonSoft.Json.

I'm not a fan of this solution. You'll end up with null properties where the serializer stopped because it encountered a cycle.

But all of that is beside the point. You don't need to change your data model or JSON serializer settings to get around this issue. The issue is that you're exposing your data model in the first place.

Suggestion: use response models

The proper solution is to map your entities to response/view models or DTOs instead. This allows you to format proper responses, and it allows your data model to evolve without interfering with your response model.

Example:

public class ForumPostResponse
{
    public int Id { get; set; }

    public string Title { get; set; }

    public List<Tag> Tags { get; set; }
}

public class TagResponse
{
    public string Name { get; set; }

    public string Description { get; set; }
}

You could also format ForumPostResponse.Tags as a list of string instead, in case you only want a list of tag names on forum posts, and include the description in other responses. Anything's possible.

You do need to write extra code to handle the mapping between objects, but it's a small tradeoff for a much nicer and more maintainable design. And besides, there are several libraries that simplify the process, the most popular being AutoMapper.

over 4 years ago · Santiago Trujillo Report

0

I know this might not be the best solution for circular reference on serialization, but an workaround can be initializing the list property:

public class ForumPost
{
    [Key]
    public int Id { get; set; }
    public string Title { get; set; }
    // ...some other properties
    public List<Tag> Tags { get; set; } = new List<Tag>();
}

public class Tag
{
    [Key]
    public string Name { get; set; }
    public string Description { get; set; }
    // ...some other properties
    public List<ForumPost> Posts { get; set; } = new List<ForumPost>();
}

Also, due to initialization, you can manipulate those lists without worrying about null exeptions and all that stuff. But note, there might be a better solution for this problem.

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!