问题
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)......
回答1:
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.
回答2:
public static IQueryable<Person> FilterHairColors(this IQueryable<Person> subQuery, string[] hairColors)
{
var result = new Person[] { }.AsQueryable();
var contains = new Dictionary<string, Expression<Func<Person, bool>>>();
contains.Add("1", p => p.HairColor_bright);
contains.Add("2", p => p.HairColor_brown);
contains.Add("3", p => p.HairColor_dark);
contains.Add("4", p => p.HairColor_red);
foreach (var color in hairColors)
{
result = subQuery.Where(contains[color]).Union(result);
}
return result;
}
来源:https://stackoverflow.com/questions/11067226/how-should-i-initialize-iqueryable-variables-before-use-a-union-expression