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

C# 实体框架核心.Include()问题,c#,entity-framework-core,C#,Entity Framework Core,一直在玩ef core的游戏,并且对include语句有异议。对于这段代码,我得到了2家公司,这是我所期望的 公共IEnumerable GetAllCompanys(HsDbContext db) { var c=db.公司; 返回c; } 这是回报 [ { “id”:1, “公司名称”:“新”, “管理员”:空, “雇员”:空, “课程”:空 }, { “id”:2, “公司名称”:“测试公司”, “管理员”:空, “雇员”:空, “课程”:空 } ] 正如您所看到的,有2家公司,所有相

一直在玩ef core的游戏,并且对include语句有异议。对于这段代码,我得到了2家公司,这是我所期望的

公共IEnumerable GetAllCompanys(HsDbContext db) { var c=db.公司; 返回c; } 这是回报

[
{
“id”:1,
“公司名称”:“新”,
“管理员”:空,
“雇员”:空,
“课程”:空
},
{
“id”:2,
“公司名称”:“测试公司”,
“管理员”:空,
“雇员”:空,
“课程”:空
}
]
正如您所看到的,有2家公司,所有相关属性都为空,因为我没有使用任何include,这正是我所期望的。现在,当我将该方法更新为:

公共IEnumerable GetAllCompanys(HsDbContext db) { var c=db.公司 .包括(t=>t.员工) .Include(t=>t.Admins) .ToList(); 返回c; } 这就是它的回报:

[
{
“id”:1,
“公司名称”:“新”,
“管理员”:[
{
“id”:2,
“名字”:“用户”,
“姓”:“1”,
“公司ID”:1
}
]
}
]
它只返回一个公司,并且只包含管理员。为什么不包括这两家公司及其员工

上市公司
{
公共int Id{get;set;}
公共字符串CompanyName{get;set;}
公共列表管理员{get;set;}
公共列表雇员{get;set;}
公共列表课程{get;set;}
公共字符串GetFullName()
{
返回公司名称;
}
}
公营雇员
{
公共int Id{get;set;}
公共字符串名{get;set;}
公共字符串姓氏{get;set;}
public int CompanyId{get;set;}
[外键(“公司ID”)]
上市公司{get;set;}
公共ICollection Employeecourses{get;set;}
}
公共类管理员
{
公共int Id{get;set;}
公共字符串名{get;set;}
公共字符串姓氏{get;set;}
public int CompanyId{get;set;}
[外键(“公司ID”)]
上市公司{get;set;}
}

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

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

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

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

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();
}
公共静态iquiryable IncludeMultiple(
这是可靠的消息来源,
列出navigationPropertyPath),其中tenty:class
{
foreach(navigationPropertyPath中的变量navExpression)
{
source=source.Include(navExpression);
}
返回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());
}
public异步任务FindOne(isspecification规范)
{
返回wait Task.Run(()=>Context.Set().AsQueryable().IncludeMultiple(spec.IncludeExpression())。其中(spec.issatifiedby).FirstOrDefault());
}
用法:

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

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

var challenge = await this._blogRepository.FindOne(blogSpec);
List nestedObjects=new List{new Rules()};
isSpecification blogSpec=新的blogSpec(blogId,嵌套对象);
var challenge=等待此消息。_blogprepository.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;
    }
}
公共类BlogSpec:SpecificationBase
{
只读int_blogId;
私有只读列表_嵌套对象;
public ChallengeSpec(int blogid,列出嵌套对象)
{
这个。_blogId=blogId;
_嵌套对象=嵌套对象;
}
公共重写表达式SpecExpression
{
获取{return blogSpec=>blogSpec.Id==this.\u blogId;}
}
公共覆盖列表IncludeExpression()
{
List tobeIncluded=新列表();
如果(_nestedObjects!=null)
foreach(变量nestedObject in_nestedObjects)
{
如果(嵌套对象是规则)
{
表达式expr=blog=>blog.Rules;
添加(expr);
}
}
返回被包括在内;
}
}

如果有帮助,我会很高兴的。请注意,这不是一个可用于生产的代码。

我知道这是一个老问题,但它是谷歌的最高结果,所以我把我找到的解决方案放在这里。对于核心3.1 web项目,有一个快速修复方法。 添加nuget软件包Microsoft.EntityFrameworkCore.Proxies。 然后,在配置服务时,只需在选项生成器中指定。文件:


我的EF资料保存在一个单独的类库中,因此我可以通过多个公司应用程序重用它。因此,当特定应用程序不需要时,具有不延迟加载的能力是非常有用的。因此,出于可重用性的目的,我更喜欢传递构建选项。但这两种方法都可以。

您是否在EF 6或更低版本上尝试过相同的代码?您的EF版本是什么?@Mafii,它是EF Core-EF 7,请参阅标题您是否可以包括您的类定义和映射?我和@JohnMorrison有同样的问题,虽然@MohammadAkbari下面接受的答案确实解决了这个问题,但这意味着我的模型失去了任何类型的强输入。MS docs()说明了include应该可以工作,以及如何使用entryapi实现它,尽管出于各种原因,我不希望在API中公开上下文。我正在将我的
DbContext
注入到我的存储库中。关于导致此问题的原因以及如何解决此问题的进一步想法,以便
Include()
o
public void ConfigureServices(IServiceCollection services) {    
    services.AddDbContextPool<YourDbContext>(options => {
        options.UseLazyLoadingProxies();
        options.UseSqlServer(this.Configuration.GetConnectionString("MyCon"));
    });
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
    optionsBuilder.UseLazyLoadingProxies();
}