Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how should I initialize IQueryable variables, before use a Union expression?

I've created an extension method over IQueryable type, which takes a subset of entities and filters them upon some criterrions. My problem is that I can't return a Union expression made of the variables, without all being initialized first. Null values, as aprears, are not valid.

public static IQueryable<Person> FilterHairColors(this IQueryable<Person> subQuery, string[] hairColors)
    {
        IQueryable<Person> q1 = null;
        IQueryable<Person> q2 = null;
        IQueryable<Person> q3 = null;
        IQueryable<Person> q4 = null;

        foreach (var value in hairColors)
        {
            switch (value)
            {
                case "1":
                    q1 = subQuery.Where(p => p.HairColor_bright == true);
                    break;
                case "2":
                    q2 = subQuery.Where(p => p.HairColor_brown == true);
                    break;
                case "3":
                    q3 = subQuery.Where(p => p.HairColor_dark == true);
                    break;
                case "4":
                    q4 = subQuery.Where(p => p.HairColor_red == true);
                    break;
            }
        }
        return q1.AsQueryable().Union(q2.AsQueryable()).Union(q3.AsQueryable()).Union(q4.AsQueryable());
    }

The presented code block is part of several more, and each produces a subset of data, conveyed to a subsequent filtering method this way:

results = persons.FilterGender(vm.gender).FilterAge(vm.age).FilterHeight(vm.height)......  
like image 783
Tal l Avatar asked Jun 16 '12 21:06

Tal l


1 Answers

Don't call Union when one of the arguments is null.

What does a "null-query" mean to you? If it means "no rows" then just don't Union it. If it means "all rows" you don't need to union because you can just take the underlying, unfiltered query.

Like this:

var result = new [] { q1, q2, q3, q4, }.Where(query => query != null).Aggregate(Queryable.Union);

This is using LINQ-to-Objects to construct a LINQ-to-SQL query.

A new version:

var result = dataContext.Persons.Where(_ => false);
if(q1 != null) result = result.Union(q1);
if(q2 != null) result = result.Union(q2);
if(q3 != null) result = result.Union(q3);
if(q4 != null) result = result.Union(q4);

The SQL Server query optimizer will remove the first dummy query so that it has no runtime cost at all.

like image 52
usr Avatar answered Nov 10 '22 14:11

usr