1
votes

I need to return the full json object (including child json objects), however I'm getting an error... The entity was imported from the database.

error

Self referencing loop detected with type 'System.Data.Entity.DynamicProxies.PhoneNumber_C240BC86FA502D917EFDFC445D42023BBD311F87B9B79339114CAC180EEC83F1'. Path '[0].UserProfile.PhoneNumbers[0].PhoneNumberType.PhoneNumbers'.

Entity

[Table("UserProfile")]
public partial class UserProfile
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public UserProfile()
    {
        PhoneNumbers = new HashSet<PhoneNumber>();
        Users = new HashSet<User>();
        UserEmails = new HashSet<UserEmail>();
    }

    public int Id { get; set; }

    [Column(TypeName = "datetime2")]
    public DateTime? dte_modified { get; set; }

    public string firstname { get; set; }

    public string lastname { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<PhoneNumber> PhoneNumbers { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<User> Users { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<UserEmail> UserEmails { get; set; }
}

Api Controller

    [HttpGet]
    [Route("")]
    public IHttpActionResult Get()
    {
        var result = _repository.GetAllUsers();

        return Json(result);
    }

repository

        public IEnumerable<User> GetAllUsers()
    {
        return _context.Users.ToList();
    }
2
You might have a look at my answer on “Self Referencing Loop Detected” exception with JSON.Net page.Murat Yıldız

2 Answers

2
votes

Your issue is caused by one feature of Entity Framework called Lazy Loading, that is enabled by default, and that exception is thrown is because your json serializer is trying to access to each property on an User instance. Property access triggers lazy loading, so more entities get serialized. On those entities properties are accessed, and even more entities are loaded and, as your case, that could end trying to serialize self referencing loops, which is detected by your json serializer.

If you want to load only the scalar properties of User entity, you can disable lazy loading in your context:

public class YourContext : DbContext 
{ 
    public YourContext() 
    { 
        this.Configuration.LazyLoadingEnabled = false; 
        this.Configuration.ProxyCreationEnabled = false; 
    } 
}

If you want to load a related entities as part of your query, you can use Include extension method:

public IEnumerable<User> GetAllUsers()
{
    return _context.Users.Include(u=>u.Users).Include(u=>u.UserEmails).ToList();
}

Another solution is, as was suggested by @DOTang, create a DTO class to project only the data that you need to show in your View.

Update:

Now I found an excellent reference where explain several ways to solve this issue.

2
votes

Self-referencing means there is a loop in serilization. It looks like your Phone Numbers has a PhoneNumberType, and the PhoneNumberType has a collection of PhoneNumbers, thus the infinite loop as outlined in the error message. You would be better to convert your collection of objects into a flat ViewModel/Model first that doesn't have any circular dependencies.

So a UserProfileViewModel would have a collection of PhoneNumberViewModels and a PhoneNumberViewModel may have something like this:

public class PhoneNumberViewModel
{
  public string Number {get; set;}
  public string Type {get; set; }
  //other relevant data
}

Where the Type is simply the name of the name, and not the whole object. Feel free to also include any other information the page is showing/info is being used, but you should typically always do this with any sort of ajax call, only return exactly what you need. This removes the circular loop.