问题 实体框架核心.Include()问题


一直在玩ef核心,并且在include语句中遇到了问题。对于这个代码我得到2家公司,这是我所期望的。

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

这回来了

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

正如你所看到的,有两家公司,所有相关的属性都是null,因为我曾经使用任何包含,这是我所期望的。现在当我将方法更新为:

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

    return c;
}

这就是它的回报:

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

它只返回一家公司,只包括管理员。为什么不包括2家公司及其员工?

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

1206
2017-07-24 09:59


起源

您是否尝试使用EF 6或更低版本的相同代码? - Roman Doskoch
您的EF版本是什么? - Mafii
@Mafii,它是EF Core - EF 7,看标题 - Roman Doskoch
你可以包括你的类定义和映射吗?预期的是什么? - DevilSuichiro
我和@JohnMorrison有同样的问题,虽然下面@MohammadAkbari接受的答案解决了这个问题,但这意味着我的模型失去了任何强类型。 MS文档(docs.microsoft.com/en-us/ef/core/querying/related-data)显示include应该工作,以及如何使用Entry API实现它,尽管由于各种原因我不想在我的API中公开上下文。我注射了我的 DbContext 进入我的存储库。关于导致这个问题的原因以及如何解决这个问题的任何进一步的想法 Include() 按预期运作? - Ashley Bye


答案:


我不确定你是否已经看到了接受的答案 ,但问题是JSON Serializer如何处理循环引用。有关更多参考资料的详细信息和链接可以在上面的链接中找到,我建议深入研究这些内容,但简而言之,添加以下内容 startup.cs 将配置序列化程序忽略循环引用:

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

12
2017-12-30 12:04



我不相信这个问题与JSON有任何关系。 - Langdon
我不同意,尽管@JohnMorrison完全有可能只使用JSON作为表达输出的便捷方式。它当然看起来像一个序列化器参考循环处理问题,但由于使用JSON来显示输出,它很可能看起来那样。为什么不让OP说明在downvoting之前是否就是这种情况? - Ashley Bye
Accutaly这是解决它的方法。非常感谢! - LaPuyaLoca
为一个非常好的提示+1真的帮助了我。现在,我已经尝试将处理设置为 错误 代替 忽视 只是为了看看会发生什么但是没有异常被抛出。邮递员得不到任何回报(甚至没有未填充子字段的列表)。但是没有500状态或任何报告回来。当我尝试在本地执行代码并断点时,VS也不会弹出任何东西。想到了吗? (使用Core 2 / EF 7 for COre 2.) - DonkeyBanana


我测试你的代码,我的测试中存在这个问题。在这篇文章中 链接 建议使用数据投影。对于你的问题如下所示,是工作。

[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
2017-07-26 04:35



是的,这种方式有效。谢谢。所以你认为它是实体框架上延迟加载的问题吗? - John Morrison
当使用包含加载方法时,eagerloading,并在第一次查询中加载数据 - Mohammad Akbari


EF Core无法进行延迟加载。 请参考这里

或者,您可以使用预先加载。

读这个 文章 

下面是我为实现预先加载而创建的扩展方法。

扩展方法:

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

存储库调用:

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

用法:

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

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

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

依赖关系:

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

如果它有帮助会很高兴。请注意,这不是生产就绪代码。


0
2017-07-12 09:28