Programmer1234
Programmer1234

Reputation: 23

Entity Framework include only returning part of the database data

I am very new to asp.net and C# so bear with me. I am trying to return data from a database using the entity framework .include() method so that I can get the foreign key information from another table. However, what is being returned is only part of the data. It seems to be cut off before everything is returned.

"[{"id":11,"name":"Mr. Not-so-Nice","heroType":3,"heroTypeNavigation":{"id":3,"type":"Villian","heroes":["

Which gives me the error: SyntaxError: Unexpected end of JSON input.

Please seem below for the model classes and the GET section of the controller where this is being returned. If I remove the "include()" method it returns all the heroes from the main table just fine.

public partial class Hero
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int? HeroType { get; set; }

    public virtual HeroTypes HeroTypeNavigation { get; set; }
}

{
public partial class HeroTypes
{
    public HeroTypes()
    {
        Heroes = new HashSet<Hero>();
    }

    public int Id { get; set; }
    public string Type { get; set; }

    public virtual ICollection<Hero> Heroes { get; set; }
}

// GET: api/Heroes
    [HttpGet]
    public async Task<ActionResult<IEnumerable<Hero>>> GetHeroesTable()
    {
        return await _context.HeroesTable.Include(hero => hero.HeroTypeNavigation).ToListAsync();   
    }

Upvotes: 2

Views: 1182

Answers (1)

Steve Py
Steve Py

Reputation: 34773

Serializer recursion rules will be tripping this up. Basically as jonsca mentions, you have a circular reference between hero, and hero type. The serializer will start with the hero, then go to serialize the hero type which it will find the Hero's collection and expect to serialize, which each would reference a hero type, with collections of Heros.. The serializer bails when it sees this.

I would recommend avoiding passing back Entity classes to your view to avoid issues with EF and lazy loading. Serialization will iterate over properties, and this will trigger lazy loads. To avoid this, construct a view model for the details your view needs, flatten as necessary.

For example if you want to display a list of Heroes with their Type:

public class HeroViewModel
{
    public int HeroId { get; set; }
    public string Name { get; set; }
    public string HeroType { get; set; }
}

to load:

var heroes = await _context.HeroesTable.Select(x => new HeroViewModel
{
    HeroId = x.HeroId,
    Name = x.Name,
    HeroType = x.HeroType.Type
}).ToListAsync();

You can utilize Automapper for example to help translate entities to view models without that explicit code using ProjectTo<TEntity> which can work with EF's IQueryable implementation.

  • With larger realistic domains your client likely won't need everything in the object graph.
  • You won't expose more information than you need to. (I.e. visible via debugging tools)
  • You'll get a performance boost from not loading the entire graph or triggering lazy load calls, and it's less data across the wire.

The last point is a rather important one as with complex object graphs, SQL can do a lot of the lifting resulting in a much more efficient query than loading "everything". Lazy hits to the database can easily add several seconds to each and every call from a client, and loading large graphs has a memory implication on the servers as well.

Upvotes: 2

Related Questions