首页 > 解决方案 > EF Core Include()\ThenInlude() 只为每个集合项添加一个条目

问题描述

构建从现有数据库公开数据的 ASP.NET Core API。所有必需的实体都基于来自几个表的数据,因此为每个实体创建了一个视图。API 输出 - 具有实体 hierachy 的 JSON,使用 DbSet 之间的包含创建。

有父实体Projects,其中包括子Components,其中包括Users等等,但它们不是问题的一部分。简化的 DTO:

    public class RrojectDTO
    {
        public int projectId { get; set; }
        public string componentCode { get; set; }
        public virtual ICollection<ComponentDTO> componentsArray { get; set; }
    }
    
    public class ComponentDTO
    {
         public Guid componentId { get; set; }
         public virtual RrojectDTO Project { get; set; }
         public string componentCode { get; set; }
         public virtual ICollection<UserDTO> usersArray { get; set; }
         ...
    }

    public class UserDTO
    {
         public int userId { get; set; }
         public virtual ComponentDTO Component { get; set; }
         public Guid componentId { get; set; }
         ...
    }

下面是 DBContext 类的样子:

public MyDbContext(DbContextOptions options)
   : base(options)
    {
        ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTrackingWithIdentityResolution;            
    }

    public virtual DbSet<ProjectDTO> Projects{ get; set; }
    public virtual DbSet<ComponentDTO> Components { get; set; }
    public virtual DbSet<UserDTO> Users { get; set; }
    ....


    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {

        modelBuilder.Entity<ProjectDTO>(entity =>
        {
            entity.HasKey(f => f.componentCode);
            entity.ToView("ProjectsArrayView", "LAB");
            entity.HasMany(p => p.componentsArray).WithOne(t => t.Project)
            .HasForeignKey(t => t.componentCode);

        });

        modelBuilder.Entity<ComponentDTO>(entity =>
        {
            entity.HasKey(f => f.componentId);
            entity.ToView("ComponentArrayView", "LAB");
            entity.HasMany(p => p.usersArray).WithOne(t => t.Component)
            .HasForeignKey(t => t.componentId);
            ....
        });

        modelBuilder.Entity<UserDTO>(entity =>
        {
            entity.HasKey(f => f.userId);
            entity.ToView("UsersArrayView", "LAB");
            ...
        });

我将这些实体与下一个代码连接起来:

`var projects = context.Projects.Where(p => p.projectId == Guid.Parse("9C373F8F-CAB8-4914-83D9-4864B2E3E7B3")).Include(co => co.componentsArray).ThenInclude(j => j.usersArray).ToList();`

最初有更多包含项目,但其他似乎工作正常。虽然示例中的一个不能按预期工作,例如:有一个项目,有 3 个组件,相同的 2 个用户(User1 和 User2)正在处理每个组件,如果您通过关键参数查询每个 dbSet,您应该可以看到对应的数据。项目输出:1 个项目 -> 包含 3 个组件 ->每个组件仅包含 1 个用户而不是两个。

我的问题是:为什么 .ThenInlcude() 每个组件只添加 User1 ,但忽略 User2 ?我在这里想念什么?

如果我只查询组件 DbSet 和 Include(x=> x.usersArray) - 结果仍然相同,每个组件都是 User1。此外,如果我要添加 User3、User4 - 它仍然是 User1 填充的。

当我通过 SQL 探查器找到查询时,它确实包含两个用户(由于策略而无法共享查询)。看了 20 篇文章,但我想我在这里遗漏了一些基本的东西,如果我可以添加一些东西来使这个问题变得更好,请告诉我。

标签: c#entity-framework.net-coreentity-framework-core

解决方案


它是一个关系数据库。每个深层记录都应该有所有先前级别的键。我看不到您的用户如何与组件相关联。如果每个用户只能在一个组件上工作或创建包含 userId 和 componentId 的 UserComponent 表以​​保持多对多关系,请添加到您的类 UserDto componentId 外键。

public class UserDTO
    {
         public int userId { get; set; }
         public int componentId {get;set;}
         public virtual ComponentDTO Component { get; set; }
         public Guid projectId  { get; set; }
         ...
    }

推荐阅读