C# 查询需要在.ThenInclude using.Where子句之后进行筛选

C# 查询需要在.ThenInclude using.Where子句之后进行筛选,c#,entity-framework,.net-core,entity-framework-core,C#,Entity Framework,.net Core,Entity Framework Core,我使用下面的查询来过滤我想要的内容 var query = await _dbContext.TargetItems .Include(i => i.BranchTargetItem) .ThenInclude(i => i.BranchTarget) .Where(x=> x.BranchTargetItem.Any(x=> x.BranchTarget.Any(x=> x.BranchId.Equa

我使用下面的查询来过滤我想要的内容

var query = await _dbContext.TargetItems                
.Include(i => i.BranchTargetItem)
.ThenInclude(i => i.BranchTarget)                
.Where(x=> x.BranchTargetItem.Any(x=> x.BranchTarget.Any(x=> x.BranchId.Equals("9417"))))
.ToListAsync(cancellationToken);
上面的表达式创建了以下SQL,我认为是
.Any()
导致了这些
左Join
语句

SELECT *
  FROM PERF_TARGET_ITEMS "p"
  LEFT JOIN (SELECT *
               FROM PERF_BRANCH_TARGET_ITEMS "p0"
               LEFT JOIN PERF_BRANCH_TARGETS "p1"
                 ON "p0".BTI_ID = "p1".BT_BRANCH_TARGET_ITEM_ID) "t"
    ON "p".TI_ID = "t".BTI_ITEM_TARGET_ITEM_ID
 WHERE EXISTS (SELECT 1
          FROM PERF_BRANCH_TARGET_ITEMS "p2"
         WHERE ("p".TI_ID = "p2".BTI_ITEM_TARGET_ITEM_ID)
           AND EXISTS
         (SELECT 1
                  FROM PERF_BRANCH_TARGETS "p3"
                 WHERE ("p2".BTI_ID = "p3".BT_BRANCH_TARGET_ITEM_ID)
                   AND ("p3".BT_BRANCH_ID = N'9417')))
 ORDER BY "p".TI_ID, "t".BTI_ID, "t".BT_ID
但是我想将
左连接
转换为
内连接
,如下所示

  SELECT *
    FROM WESTCORE.PERF_BRANCH_TARGET_ITEMS "p"
   INNER JOIN WESTCORE.PERF_PERIODS "p0"
      ON "p".BTI_ITEM_PERIOD_ID = "p0".P_ID
   INNER JOIN WESTCORE.PERF_TARGET_ITEMS "p1"
      ON "p".BTI_ITEM_TARGET_ITEM_ID = "p1".TI_ID
    LEFT JOIN (SELECT *
                 FROM WESTCORE.PERF_BRANCH_TARGETS "p2"
                WHERE "p2".BT_BRANCH_ID = '9417') "t"
      ON "p".BTI_ID = "t".BT_BRANCH_TARGET_ITEM_ID
   WHERE ((SELECT COUNT(*)
             FROM WESTCORE.PERF_BRANCH_TARGETS "p3"
            WHERE ("p".BTI_ID = "p3".BT_BRANCH_TARGET_ITEM_ID)
              AND ("p3".BT_BRANCH_ID = '9417')) > 0)
   ORDER BY "p".BTI_ID, "p0".P_ID, "p1".TI_ID, "t".BT_ID
我想返回包含其关系实体的
TargetItems
(TargetItems>BranchTargetItems>BranchTargets)

编辑:

我只想添加这个过滤器,
。然后包括(bti=>bti.BranchTarget)。其中(bt=>bt.BranchId.Equals(“9417”)
到下面的查询中

    var query = await _dbContext.TargetItems
        .Include(ti => ti.BranchTargetItem)
        .ThenInclude( bti=> bti.BranchTarget)
        .ToListAsync(cancellationToken);
编辑:

我已经用下面的查询解决了这个问题,但我仍然在寻找理想的解决方案

编辑:

我也尝试过这种方法,TargetItems实体在这里与自身有一对多的关系,
[DataMember]public virtual ICollection TargetItems{get;set;}
当我应用下面的代码时,子节点是空的。它只返回第一个节点

    var targetItems = await _dbContext.BranchTargets
                    .Where(x => x.BranchId.Equals("9417"))
                    .Include(t => t.BranchTargetItem)
                    .ThenInclude(t => t.TargetItem)
                    .Select(x=> x.BranchTargetItem.TargetItem)
                    .ToListAsync(cancellationToken);

这不是你应该担心的任何问题<代码>任何->
存在
。您的问题是
Include
,它转化为
左外连接
。所以你需要额外的过滤,比如:

var query = await _dbContext.TargetItems
.Include(i => i.BranchTargetItem)
.Where(e => e.BranchTargetItem != null) //added filtration
.ThenInclude(i => i.BranchTarget)
.Where(e => e.BranchTarget != null) //added filtration
.Where(x => x.BranchTargetItem.Any(x => x.BranchTarget.Any(x => x.BranchId.Equals("9417"))))
.ToListAsync(cancellationToken);

如果需要
内部联接
,则需要使用
联接
。可以优化预期的
SQL
查询,并将其简化为:

SELECT *
FROM 
    WESTCORE.PERF_BRANCH_TARGET_ITEMS p
INNER JOIN WESTCORE.PERF_PERIODS p0 ON p.BTI_ITEM_PERIOD_ID = p0.P_ID
INNER JOIN WESTCORE.PERF_TARGET_ITEMS p1 ON p.BTI_ITEM_TARGET_ITEM_ID = p1.TI_ID
INNER JOIN WESTCORE.PERF_BRANCH_TARGETS p2 ON p.BTI_ID = p2.BT_BRANCH_TARGET_ITEM_ID
WHERE 
    p2.BT_BRANCH_ID = '9417'
ORDER BY 
    p.BTI_ID
,   p0.P_ID
,   p1.TI_ID
,   p2.BT_BRANCH_TARGET_ITEM_ID
要应用此功能,您可以执行以下操作:

var query = await _dbContext.BranchTargetItem
            .Join(_dbContext.TargetItems,
                bti => bti.BranchId, 
                ti  => ti.BranchId,
                (bti, ti) => new { TargetItems = ti, BranchTargetItem = bti })
            .Join(_dbContext.BranchTarget,
                ti => ti.TargetItems.BranchId,
                bt => bt.BranchId, 
                (bti, ti) => new { TargetItems = ti, BranchTarget = bt })           
            .Where(x=> x.TargetItems.BranchId.Equals("9417"))
            .ToListAsync(cancellationToken);

查询本身需要测试并调整到正确的实体。

如果您只希望
分支目标
与where子句匹配,则需要将其作为查询的主要详细信息记录,然后包括其父记录

var query=await\u dbContext.BranchTarget
其中(x=>x.BranchId.Equals(“9417”))
.Include(t=>t.branchtargetims)
.然后包括(t=>t.TargetItems)
.ToListSync(取消令牌);
对原始问题的回答 我使用下面的查询来过滤我想要的内容

var query = await _dbContext.TargetItems                
.Include(i => i.BranchTargetItem)
.ThenInclude(i => i.BranchTarget)                
.Where(x=> x.BranchTargetItem.Any(x=> x.BranchTarget.Any(x=> x.BranchId.Equals("9417"))))
.ToListAsync(cancellationToken);
var query=await\u dbContext.TargetItems
.包括(i=>i.BranchTargetItem)
.然后包括(i=>i.BranchTarget)
其中(x=>x.BranchTargetItem.Any(x=>x.BranchTarget.Any(x=>x.branchHid.Equals(“9417”))
.ToListSync(取消令牌);
但我想将左连接转换为内连接[…]

要解决您原来的问题,一个简单的解决方案是颠倒您的包含顺序:

var branchTargets=context.branchTargets
.包括(bt=>bt.BranchTargetItem)
.然后包括(bti=>bti.TargetItem)
.其中(bt=>bt.BranchId==“9417”)
.ToList();
这将使用
内部联接
s并返回
分支目标
实体,从中可以通过
分支目标[0]到达
目标项目
实体。分支目标项目.目标项目

选择[p].[BT_分支机构目标机构目标机构项目ID],[p].[BT_分支机构ID],[p].[BT_ID],[p0].[BTI_ID],[p0].[BTI_项目目标机构项目ID],[p1].[TI_ID]
从[PERF_BRANCH_TARGETS]到[p]
[p].[BT\U ID]=[p0].[BTI\U ID]上的[p0]内部联接[PERF\U BRANCH\U TARGET\U ITEMS]
在[p0]上将[PERF_TARGET_ITEMS]作为[p1]进行内部联接。[BTI_ITEM_TARGET_ITEM_ID]=[p1]。[TI_ID]
其中[p].[BT_分支机构ID]=N'9417'
如果不希望查询返回
BranchTarget
作为根实体,可以执行以下操作:

var targetItems=context.BranchTargets
.包括(bt=>bt.BranchTargetItem)
.然后包括(bti=>bti.TargetItem)
.其中(bt=>bt.BranchId==“9417”)
.可计算的()
.选择(bt=>bt.BranchTargetItem.TargetItem)
.ToList();
下面是一个完全工作的示例控制台项目,它演示了这种方法:

使用系统;
使用System.Collections.Generic;
使用系统诊断;
使用System.Linq;
使用System.Threading.Tasks;
使用Microsoft.EntityFrameworkCore;
使用Microsoft.Extensions.Logging;
命名空间IssueConsoleTemplate
{
公共类目标
{
public int TargetItemId{get;set;}
公共ICollection分支目标{get;set;}
}
公共类分支目标
{
public int BranchTargetItemId{get;set;}
public int ItemTargetItemId{get;set;}
公共TargetItem TargetItem{get;set;}
公共ICollection分支目标{get;set;}
}
公共类分支目标
{
public int BranchTargetId{get;set;}
公共字符串{get;set;}
public int BranchTargetItemId{get;set;}
公共BranchTargetItem BranchTargetItem{get;set;}
}
公共类上下文:DbContext
{
公共DbSet TargetItems{get;set;}
公共数据库集分支目标{get;set;}
公共数据库集分支目标{get;set;}
配置时受保护的覆盖无效(DBContextOptions Builder Options Builder)
{
选项生成器
.UseSqlServer(
@“数据源=。\MSSQL14;集成安全性=SSPI;初始目录=SO636238”)
.UseLoggerFactory(
LoggerFactory,创建(
b=>b
.AddConsole()
.AddFilter(level=>level>=LogLevel.Information)))
.EnableSensitiveDataLogging()
.EnableDetailedErrors();
}
模型创建时受保护的覆盖无效(ModelBuilder ModelBuilder)
{
modelBuilder.Entity(
实体=>
{
实体。ToTable(“性能目标项目”);
Property(e=>e.TargetItemId)
.HasColumnName(“TI_ID”);
entity.HasMany(x=>x.BranchTargetItem)
.WithOne(x=>x.TargetItem)
SELECT *
FROM 
    WESTCORE.PERF_BRANCH_TARGET_ITEMS p
INNER JOIN WESTCORE.PERF_PERIODS p0 ON p.BTI_ITEM_PERIOD_ID = p0.P_ID
INNER JOIN WESTCORE.PERF_TARGET_ITEMS p1 ON p.BTI_ITEM_TARGET_ITEM_ID = p1.TI_ID
INNER JOIN WESTCORE.PERF_BRANCH_TARGETS p2 ON p.BTI_ID = p2.BT_BRANCH_TARGET_ITEM_ID
WHERE 
    p2.BT_BRANCH_ID = '9417'
ORDER BY 
    p.BTI_ID
,   p0.P_ID
,   p1.TI_ID
,   p2.BT_BRANCH_TARGET_ITEM_ID
var query = await _dbContext.BranchTargetItem
            .Join(_dbContext.TargetItems,
                bti => bti.BranchId, 
                ti  => ti.BranchId,
                (bti, ti) => new { TargetItems = ti, BranchTargetItem = bti })
            .Join(_dbContext.BranchTarget,
                ti => ti.TargetItems.BranchId,
                bt => bt.BranchId, 
                (bti, ti) => new { TargetItems = ti, BranchTarget = bt })           
            .Where(x=> x.TargetItems.BranchId.Equals("9417"))
            .ToListAsync(cancellationToken);
var query = (
    from ti in _dbContext.TargetItems
    join bti in _dbContext.BranchTargetItem on ti.Id = bti.ItemTargetItemId
    join bt in _dbContext.BranchTarget on bti.Id = bt.BranchTargetItemId
    where bt.BranchId.Equals("9417")
    select new {
           ti, 
           btis = ti.BranchTargetItem, 
           bts  = ti.BranchTargetItem.SelectMany(x=> x.BranchTarget)
       }
).ToListAsync();