如何从 linq 的查询结果中排除?

How to exclude from query's result in linq?

在第一张图片中,我有第一个查询的结果,突出显示的部分表示将通过在第二个查询上应用过滤器来排除的行,在第二个图片中,我有查询的结果 select * from exlusion_table

我必须更改第一个查询以使其排除从第二个查询中检索到的项目

第一个查询:

var u = from a in cx.VW_LIST
        where (a.PRJ == codPrj) && (a.DATE > date_ || a.DATE == null || date_ == null)
        && (x.Contains(a.CODE) || x.Count() == 0)
        select a)

第二个查询:

var y = from esc in cx.EXCLUSION select esc

应修改第一个查询以排除所有具有值 fcode = 第二个查询的 fcode(在第二个查询的 fscode = null 的情况下)或那个(fcode = fcode of第二个查询 && fscode = 第二个查询的 fscode )

您可以使用 Any()。即:

var u = from a in cx.VW_LIST
        where (a.PRJ == codPrj) 
           && (a.DATE > date_ || a.DATE == null || date_ == null)
           && (x.Contains(a.CODE) || x.Count() == 0)
           && (!cx.EXCLUSION.Any( y => x.fscode == y.fscode && x.fcode == y.fcode ))
        select a)

有两种方法,一种是使用!ANY()过滤掉在另一个列表中找到的记录,这将编译成WHERE NOT EXISTS(_exclusion_)过滤表达式

var excluded = cx.EXCLUSION.AsQueryable();

var query = from vw in cx.VW_LIST
            where vw.PRJ == codPrj
            where vw.DATE == null || date_ == null || vw.DATE > date_
            where !x.Any() || x.Contains(vw.CODE)
            where !excluded.Any(esc => vw.fcode == esc.fcode 
                                   && (esc.fscode == null || vw.fscode == esc.fscode))
            select vw;

var results = query.ToList();

棘手的元素是排除的 table 中 fscodenull,它需要作为通配符匹配,或者否定 fscode 比较。

没有必要将 excluded 查询拆分成它自己的查询,我们可以直接引用 cx.EXCLUSION table,它会产生完全相同的效果,这向您展示了一种用于构建 LINQ 查询的封装技术,您可以轻松地增加排除查找的复杂性,而不会造成整个查询的混乱。

您可能还发现需要有条件地构建查询,这就是 Fluent syntax 提供更模块化方法的地方:

bool filterExcludedRecords = true;
...
var excluded = cx.EXCLUSION.AsQueryable();

var query = cx.VW_LIST.Where(vw => vw.PRJ == codPrj)
                      .Where(vw => vw.DATE == null || date_ == null || vw.DATE > date_)
                      .Where(vw => !x.Any() || x.Contains(vw.CODE));
if(filterExcludedRecords)
    query = query.Where(vw => !excluded.Any(esc => vw.fcode == esc.fcode 
                              && (esc.fscode == null || vw.fscode == esc.fscode)));

var results = query.ToList();

外连接

另一种方法是在未找到排除匹配项的地方使用 LFET OUTER JOIN

var excluded = cx.EXCLUSION.AsQueryable();

var query = from vw in cx.VW_LIST
            where vw.PRJ == codPrj
            where vw.DATE == null || date_ == null || vw.DATE > date_
            where !x.Any() || x.Contains(vw.CODE)
            from esc in excluded.Where(e => vw.fcode == e.fcode 
                                            && (e.fscode == null || vw.fscode == e.fscode))
                                .DefaultIfEmpty()
            where esc.fscode == null
            select vw;

var results = query.ToList();

WHERE NOT EXISTS 通常在性能方面更胜一筹,OUTER JOIN 可能在 un-optimised table 或排除列表中的行数时提供更好的响应非常小,主要table中的行数非常大。

为了完整起见,我包含了这个查询选项,众所周知,您可以通过向查询添加新的 from 子句来创建简单的外部联接。