Question

I've looked around but couldn't find a solid answer. I've been thinking about this for a while, and I couldn't really think up of a good solution for this.

Let say I have 5 IEnumerable, they are all nullable, so they could be empty.

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 is an object that has an Id, name, SpeciesId, and EnvionmentId.

Now to make sense of this, here's an example of how these enumerations are grouped:

Each IEnumerable an enumeration of keys (or ids) that are found in the Genera IEnumerable.

Now, I want to be able to create scenarios based on this; where I can get a list of all animals, or a filtered list of all animals of certain species, a list of all animals of a specific environment, a list of all animals excluding certain species, and a list of all animals in every environment but excluding certain environments.

I had 2 solutions of going about this. Either 1, do a series of left joins, Genera, SepeciesIds, EnvironmentIds, and put the SpeciesIds_SubExclusion and EnvironmentIds_Exclusion in a where clause. But I was thinking that this would be too expensive of a query when not necessary, like if I wanted a list of all Genera regardless of EnvironmentIds or SpeciesIds, why would I do a join on those two?

So I came up with a solution of using if statements, and was wondering if this is the better optimized way of proceeding about this:

query is an object that contains all the IEnumerables I mentioned:

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));
}

Does anyone have any better suggestions to the above solution or is this a recommended practice of doing a series of conditional ifs to determine the final outcome of the query? I'm kind of concerned about this because more conditional ifs would be included if I add more IEnumerables on this query, as this function would keep on growing and growing into a monolith of code.

Was it helpful?

Solution

I think the following approach should work quite good:

// 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();

In where clauses data which has the right id and has not excluded id is reqested. Your joins is not requred in this case, but if you want them then you shouldn't create new instances of result objects:

GenusQuery = (from genus in GenusQuery
               join environment in query.EnvironmentIds
                   on genus.environmentId equals environment
               select genus); // not new instance, but looping variable here
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top