Entity Framework core .Include() issue

c# entity-framework-core

Question

Been having a play about with ef core and been having an issue with the include statement. For this code I get 2 companies which is what i expected.

public IEnumerable<Company> GetAllCompanies(HsDbContext db)
{
    var c = db.Company;
    return c;
}

This returns

[
    {
        "id":1,
        "companyName":"new",
        "admins":null,
        "employees":null,
        "courses":null
    },
    {
        "id":2,
        "companyName":"Test Company",
        "admins":null,
        "employees":null,
        "courses":null
    }
]

As you can see there are 2 companies and all related properties are null as i havnt used any includes, which is what i expected. Now when I update the method to this:

public IEnumerable<Company> GetAllCompanies(HsDbContext db)
{
    var c = db.Company
        .Include(t => t.Employees)
        .Include(t => t.Admins)
        .ToList();

    return c;
}

this is what it returns:

[
    {
        "id":1,
        "companyName":"new",
        "admins":[
            {
                "id":2,
                "forename":"User",
                "surname":"1",
                "companyId":1
            }
        ]
    }
]

It only returns one company and only includes the admins. Why did it not include the 2 companies and their employees?

public class Company
{
    public int Id { get; set; }
    public string CompanyName { get; set; }
    public List<Admin> Admins { get; set; }
    public List<Employee> Employees { get; set; }
    public List<Course> Courses { get; set; }

    public string GetFullName()
    {
        return CompanyName;
    }
}

public class Employee
{
    public int Id { get; set; }
    public string Forename { get; set; }
    public string Surname { get; set; }
    public int CompanyId { get; set; }
    [ForeignKey("CompanyId")]
    public Company company { get; set; }

    public ICollection<EmployeeCourse> Employeecourses { get; set; }
}

public class Admin
{
    public int Id { get; set; }
    public string Forename { get; set; }
    public string Surname { get; set; }
    public int CompanyId { get; set; }
    [ForeignKey("CompanyId")]
    public Company Company { get; set; }
}
1
18
11/26/2018 8:01:24 PM

Accepted Answer

I'm not sure if you've seen the accepted answer to this question, but the problem is to do with how the JSON Serializer deals with circular references. Full details and links to more references can be found at the above link, and I'd suggest digging into those, but in short, adding the following to startup.cs will configure the serializer to ignore circular references:

services.AddMvc()
    .AddJsonOptions(options => {
        options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
    });
28
5/23/2017 11:54:09 AM

Popular Answer

Lazy loading is not yet possible with EF Core. Refer here.

Alternatively you can use eager loading.

Read this article

Below is the extension method i have created to achieve the eager loading.

Extension Method:

public static IQueryable<TEntity> IncludeMultiple<TEntity, TProperty>(
            this IQueryable<TEntity> source,
            List<Expression<Func<TEntity, TProperty>>> navigationPropertyPath) where TEntity : class
        {
            foreach (var navExpression in navigationPropertyPath)
            {
                source= source.Include(navExpression);
            }
            return source.AsQueryable();
        }

Repository Call:

public async Task<TEntity> FindOne(ISpecification<TEntity> spec)
        {
            return await Task.Run(() => Context.Set<TEntity>().AsQueryable().IncludeMultiple(spec.IncludeExpression()).Where(spec.IsSatisfiedBy).FirstOrDefault());
        }

Usage:

List<object> nestedObjects = new List<object> {new Rules()};

            ISpecification<Blog> blogSpec = new BlogSpec(blogId, nestedObjects); 

            var challenge = await this._blogRepository.FindOne(blogSpec);

Dependencies:

public class BlogSpec : SpecificationBase<Blog>
    {
        readonly int _blogId;
        private readonly List<object> _nestedObjects;

        public ChallengeSpec(int blogid, List<object> nestedObjects)
        {
            this._blogId = blogid;
            _nestedObjects = nestedObjects;
        }

        public override Expression<Func<Challenge, bool>> SpecExpression
        {
            get { return blogSpec => blogSpec.Id == this._blogId; }
        }

        public override List<Expression<Func<Blog, object>>> IncludeExpression()
        {
            List<Expression<Func<Blog, object>>> tobeIncluded = new List<Expression<Func<Blog, object>>>();
            if (_nestedObjects != null)
                foreach (var nestedObject in _nestedObjects)
                {
                    if (nestedObject is Rules)
                    {
                        Expression<Func<Blog, object>> expr = blog => blog.Rules;
                        tobeIncluded.Add(expr);
                    }

                }

            return tobeIncluded;
        }

Will be glad if it helps. Please note this is not a production ready code.



Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow