LINQ:基于预选数据的条件连接

时间:2014-02-17 01:53:33

标签: c# linq ienumerable

我环顾四周但找不到可靠的答案。我已经考虑了一段时间了,我真的想不出一个好的解决方案。

假设我有5个IEnumerable,它们都可以为空,所以它们可能是空的。

IEnumerable<Genus> Genera
IEnumerable<string> SpeciesIds (list of keys)
IEnumerable<string> EnvrionmentIds (list of keys)
IEnumerable<string> SpeciesIds_Exclusion (list of keys)
IEnumerable<string> EnvironmentIds_Exclusion (list of keys)

Genus是一个具有Id,name,SpeciesId和EnvionmentId的对象。

现在要理解这一点,以下是这些枚举如何分组的示例:

每个IEnumerable都是在Genera IEnumerable中找到的键(或id)的枚举。

现在,我希望能够基于此创建场景;在那里我可以获得所有动物的清单,或某些物种的所有动物的过滤清单,特定环境的所有动物的清单,除某些物种之外的所有动物的清单,以及每种环境中所有动物的清单,排除某些环境。

我有两种解决方案。要么1,要执行一系列左连接,Genera,SepeciesIds,EnvironmentIds,并将SpeciesIds_SubExclusion和EnvironmentIds_Exclusion放在where子句中。但是我认为在没有必要的情况下查询会太昂贵,比如我想要一个所有Genera的列表而不管EnvironmentIds或SpeciesIds,为什么我会在这两个上加入?

所以我想出了一个使用if语句的解决方案,并且想知道这是否是更好的优化方式:

query是一个包含我提到的所有IEnumebles的对象:

var GenusQuery = query.Genera;

//the join filters down to give back the genus of animals found in the species list
if (query.SpeciesIds != null && query.SpeciesIds.Any())
{
    GenusQuery = (from genus in GenusQuery
                   join species in query.SpeciesIds
                       on genus.speciesId equals species
                   select new {
                           id = genus.id,
                           name = genus.name,
                           environmentId = genus.environmentId
                           speciesId = genus.speciesId
                   });
}

if (query.EnvironmentIds != null && query.EnvironmentIds.Any())
{
    GenusQuery = (from genus in GenusQuery
                   join environment in query.EnvironmentIds
                       on genus.environmentId equals environment
                   select new {
                           id = genus.id,
                           name = genus.name,
                           environmentId = genus.environmentId
                           speciesId = genus.speciesId
                   });
}

//I think the below fails, I haven't tested it out
if (query.SpeciesIds_Exclusion != null && query.SpeciesIds_Exclusion.Any())
{
    GenusQuery = GenusQuery.Except(x => query.SpeciesIds_Exclusion(x.speciesId));
}

if (query.EnvironmentIds_Exclusion != null && query.EnvironmentIds_Exclusion.Any())
{
    GenusQuery = GenusQuery.Except(x => query.EnvironmentIds_Exclusion.Contains(x.environmentIds));
}

有没有人对上述解决方案有任何更好的建议,或者这是建议的做一系列条件ifs以确定查询的最终结果的做法?我有点担心这个问题,因为如果我在这个查询中添加更多的IEnumerables会包含更多的条件ifs,因为这个函数会继续增长并成长为代码的整体。

1 个答案:

答案 0 :(得分:1)

我认为以下方法应该非常有效:

// check if your collections are null
var SpeciesIds = query.SpeciesIds ?? new List<string>(); 
var SpeciesIds_Exclusion = query.SpeciesIds_Exclusion ?? new List<string>();
var EnvironmentIds = query.EnvironmentIds ?? new List<string>();
var EnvironmentIds_Exclusion = query.EnvironmentIds_Exclusion ?? new List<string>();

// do the query
var GenusQuery = query.Genera
    .Where(x => SpeciesIds.Contains(x.speciesId) && 
               !SpeciesIds_Exclusion.Contains(x.speciesId))
    .Where(x => EnvironmentIds.Contains(x.environmentId) &&
               !EnvironmentIds_Exclusion.Contains(x.environmentId))
    .ToList();

在where where子句中,需要具有正确id且未排除id的数据。在这种情况下,您的联接不是必需的,但如果您需要它们,则不应创建结果对象的新实例:

GenusQuery = (from genus in GenusQuery
               join environment in query.EnvironmentIds
                   on genus.environmentId equals environment
               select genus); // not new instance, but looping variable here