如何在 Entity Framework 中对 Children Table 应用 Where 条件

How to apply Where condition on Children Table in Entity Framework

我有以下 SQL 查询,由于某些限制,因为此查询中有更多条件,我必须将此查询转换为 LINQ。

SELECT
    sh.BarCode
FROM
    Bars AS sh

    INNER JOIN BarDetail AS detail ON
        detail.BarCode = sh.BarCode
        AND
        detail.IsActive = 1

    INNER JOIN BarStatus AS st ON
        st.BarCode = sh.BarCode
        AND
        st.IsActive = 1

到目前为止我已经在 LINQ 上完成了这个

var queryAble = _context.BarDetail
    .Include(x => x.Bar)
    .Include(x => x.Bar)
    .ThenInclude(y => y.BarStatus)
    .Where(x => x.IsActive == true)
    .AsQueryable();

我也想在 barstatus 上应用条件;条件是 barstatusIsActive == true。我做不到。

我不想用 DbCommand 作为原始 SQL 来做,我想完全只使用 Linq-to-Entities 来做。

我怎么会这样,但它不起作用

var queryAble = _context.BarDetail
    .Include(x => x.Bar)
    .Include(x => x.Bar)
    .ThenInclude(y => y.BarStatus)
    .Where(x => x.IsActive == true && x.Bar.BarStatus[SOMETHING HERE])
    .AsQueryable();

这是将您的 SQL 直接转换为 LINQ。请注意,Include 引入不是为了构建查询而是为了加载相关数据。

var query =
    from bar in _context.Bar
    from detail in bar.Details
    where detail.IsActive && bar.IsActive && bar.BarStatus.IsActive
    select bar.BarCode;

正如我在评论中所说,虽然您的原始 SQL 查询 有效 ,但 JOIN 子句最好仅使用 键(或元组)相等,而其他谓词应在WHERE 子句中。遵循该模式不会对您的运行时查询执行计划造成任何更改,但我觉得它与 SQL 所基于的 relational-calculus 保持一致 - 这也意味着您可以立即检查 JOIN 是否正确,因为您将始终使用 only primary-key 和 foreign-key 列(可能已经编入索引... 对吗?).

因此您的查询变为:

SELECT
    b.BarCode
FROM
    Bars AS b
    INNER JOIN BarDetail AS d ON d.BarCode = b.BarCode
    INNER JOIN BarStatus AS s ON s.BarCode = b.BarCode
WHERE
    d.IsActive = 1
    AND
    s.IsActive = 1

...更容易翻译成Linq-to-Entities:

还有:

  • 您不需要 .AsQueryable() 调用:从 DbContextDbSet<T> 创建的所有 non-materialized 查询都已经 IQueryable<T>
  • 因为你有 navigation-properties 你不需要做一个手册 Join.
IQueryable<String> q = _context.BarCode
//  .Include( b => b.BarDetail )
//  .Include( b => b.BarStatus )
    .Where( b =>
        b.BarDetail.IsActive == true
        &&
        b.BarStatus.IsActive == true
    )
    .Select( b =>  b.BarCode );

List<String> list = await q.ToListAsync( cancellationToken ).ConfigureAwait(false);

更新:没有b.BarDetail.IsActive == true

I can not directly add Include( b => b.BarStatus ) because BarStatus doesn't have direct relationship with BarCode, its linked with BarDetail. So first we go into BarDetail and then after that we go in BarStatus using BarDetail

你仍然可以做一个手册JOIN:

IQueryable<String> q = _context.BarCode
//  .Include( b => b.BarDetail )
//  .Include( b => b.BarStatus )
    .Join( _context.BarStatus, s => s.BarCode, b => b.BarCode, ( s, b ) 
 => new { BarStatus = s, BarCode = b, BarDetail = b.BarDetail } )
    .Where( t =>
        t.BarDetail.IsActive == true
        &&
        t.BarStatus.IsActive == true
    )
    .Select( b => b.BarCode );

List<String> list = await q.ToListAsync( cancellationToken ).ConfigureAwait(false);