繁体   English   中英

Linq to Entities,在查询表达式中注入联接

[英]Linq to Entities, Inject Join Inside Query Expression

我正在尝试提高某些LINQ查询的性能,有一件小事情需要大量改进:联接。 几乎我所有的查询都有一些用于过滤结果的联接,但未选择到结果中。 这些过滤条件是可选的...

我今天所拥有的是:

var q = from t1 in context.Set<T1>() 
    where t1.mandatoryfilter >= 0
    select t1;

if (useFilter) 
{
    var q2 = from t1 in q
        from t2 in context.Set<T2>().Where(t2 => t2.fk == t1.pk).DefaultIfEmpty
        where t2.filterProperty == filterValue
        select t1;

    if (useFilter2) 
    {
        [...]

        return q3.ToList();
    }

    return q2.ToList();
} 
else 
{
    if (useFilter2) 
    {
        [...]

        return q2.ToList();
    }

    return q.ToList();
}

这将生成查询的投影。 并且根据过滤器的复杂性/数量,它会生成越来越多的投影,并且如果我需要组合一些过滤器,则需要嵌套代码。 结果查询的大小可能会变得很大,以致无法通过Internet发送(实际上不是太大的XD,但它会导致性能问题),并且代码本身也很难维护。

我知道我可以改回字符串SQL ...但这不是一个非常优雅的解决方案吗?

我想知道是否有一种方法可以注入联接,而过滤器直接执行表达式树,因此提供程序将不会生成投影,并且代码将是线性且简单的。

ps:非常重要的信息,我使用的是EF6,Linq-to-Entities,默认SqlClient。

谢谢大家。

我对LINQ的查询语法版本不太有把握,并且没有打开VS,因此我使用方法语法来确保我正确无误:但是同样的想法适用。

这是应用过滤器的相当标准的方法。 您不必每次都创建新查询,只需为每个过滤器附加一个谓词即可。 也适用于联接(除非您使用自定义联接,否则可能无需显式使用.Join

var people = context.Set<Person>()
                .Where(p => p.mandatoryFilter > 0);

if (filter.WithAddress != null)
    people = people.Where(p => p.Address == filter.WithAddress);

if (filter.WithBossName != null)
    people = people.Where(p => p.Boss.Name == filter.WithBossName);

return people.ToList();

如果使用导航属性,则几乎不需要连接,并且可以将大多数过滤条件作为单个表达式应用。

假设您的T1实体具有导航属性T2 过滤器表达式将如下所示:

q = q.Where(q.T2.filterProperty1 == filterProperty == filterValue);

您还可以在此处看到仅将表达式追加到现有查询q

现在,它变成一种常用的模式,以向IQueryable添加过滤条件:

IQueryable<T1> query = from t1 in context.Set<T1>() 
                       where t1.mandatoryfilter >= 0
                       select t1;

if (filterValue2 != null)
    query = query.Where(t => t.T2.filterProperty == filterValue2);
if (filterValue3 != null)
    query = query.Where(t => t.T3.filterProperty == filterValue3);
if (filterValue4 != null)
    query = query.Where(t => t.T4.filterProperty == filterValue4);

(请注意, queryIQueryableIQueryable ,否则分配query = query....请勿编译。)

现在,您甚至可以将过滤器应用于1:n关联

if (filterValue5 != null)
    query = query.Where(t => t.T5s.Any(t5 => t5.filterProperty == filterValue5));

如果使用join进行过滤,则无法执行此操作,因为它将使结果集相乘。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM