web-dev-qa-db-fra.com

Problème principal .Include () de Entity Framework

Vous avez eu un problème avec ef core et vous avez eu un problème avec la déclaration include. Pour ce code, je reçois 2 entreprises, ce à quoi je m'attendais.

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

Cela retourne

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

Comme vous pouvez le voir, il y a 2 sociétés et toutes les propriétés associées sont nulles car je n’avais utilisé aucun élément inclus, ce à quoi j’attendais. Maintenant, quand je mets à jour la méthode à ceci:

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

    return c;
}

voici ce qu'il retourne: 

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

Il ne renvoie qu'une seule entreprise et n'inclut que les administrateurs. Pourquoi n'inclut-il pas les 2 entreprises et leurs employés? 

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; }
}
13
John Morrison

Je ne sais pas si vous avez vu la réponse acceptée à cette question , mais le problème tient à la manière dont le sérialiseur JSON traite les références circulaires. Vous trouverez des détails complets et des liens vers plus de références sur le lien ci-dessus, et je suggérerais de les approfondir, mais en résumé, ajouter ce qui suit à startup.cs va configurer le sérialiseur pour ignorer les références circulaires:

services.AddMvc()
    .AddJsonOptions(options => {
        options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
    });
16
Ashley Bye

Le chargement différé n'est pas encore possible avec EF Core. Reportez-vous ici .

Sinon, vous pouvez utiliser un chargement rapide.

Lire ceci article

Vous trouverez ci-dessous la méthode d'extension que j'ai créée pour obtenir le chargement souhaité.

Méthode d'extension:

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();
        }

Appel de référentiel:

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);

Les dépendances:

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;
        }

Sera heureux si cela aide. Veuillez noter qu'il ne s'agit pas d'un code prêt à la production. 

1
Venkatesh

Je teste votre code, ce problème existe dans mon test. dans cet article LINK Propose d'utiliser la projection de données. pour votre problème Quelque chose comme ce qui suit, c'est du travail.

[HttpGet]
public dynamic Get()
{
    var dbContext = new ApplicationContext();

    var result = dbContext.Companies
        .Select(e => new { e.CompanyName, e.Id, e.Employees, e.Admins })
        .ToList();

    return result;
}
1
Mohammad Akbari