Search code examples
.netlinq-to-sqllambdaexpression-trees

How to preserve Linq2SQL OR between conditions?


Lets say we need to select two sets from a table: "Things"

var GradeA = db.Things.Where(t=>  condition1);
var GradeB = db.Things.Where(t=> !condition1 && condition2);
var DesiredList = GradeA.union(GradeB);

alternatively, we need to write a single statement to avoid union cost:

var DesiredList = db.Things.Where(t=> condtion1 || (!condition1 && condition2));

the problem is query optimizer seems to trim the expression to condition2 only.

How to preserve the priority between condition1 and condition2

a real life example workaround is :

/// <summary>
/// Gets only first BookTag for each tag word, chooses the one of this user (if exists).
/// </summary>
/// <param name="book"></param>
/// <returns></returns>
public static IQueryable<BookTag> UniqueByTags(this IQueryable<BookTag> bookTags, User user)
{
    return bookTags.GroupBy(BT => BT.TagId)
        .Select(g => g.Any(bt => bt.UserId == user.Id) ? 
            new BookTag() { User = user, Tag = g.First().Tag, Book = bookTags.First().Book } : 
            new BookTag() {User = g.First().User, Tag = g.First().Tag, Book = bookTags.First().Book}
            );
}

Edit:

Example is getting Auto-Complete list:

  • input: str
  • output: things that start with str and things that contain str (no duplicates)

Another Example: Selecting ThingTags which have 3 properties:

  • ThingID
  • UserID
  • TagID

we want to select only one ThingTag for each TagID under condition that we select the one with UserID equals parameter if exists, otherwise select first ThingTag for that TagID.

Still with me ? hope so :)



Solution

  • Is there any reason for not writing this:

    var DesiredList = db.Things.Where(t=> condition1 || condition2);
    

    That's logically the same set of elements, after all. As it's a simpler expression, it's more likely that the query generator will get it right. Having said that, I'm surprised it's getting it wrong. Do you have a complete example you could provide?