Modify linq query at runtime

c#, entity-framework, extension-methods, linq

Solution

Rather than overcomplicate things, how about just using an if statement?

var query = from person in container.people 
            select person;

if (userWantsStartsWith)
{
    query = from p in query
            where p.Name.Contains(some_criterion)
            select p;
}
else
{
    query = from p in query
            where p.Name.StartsWith(some_criterion)
            select p;
}

Update

If you really need something more complex try looking at LinqKit. It allows you to do the following.

var stringFunction = Lambda.Expression((string s1, string s2) => s1.Contains(s2));

if (userWantsStartsWith)
{
    stringFunction = Lambda.Expression((string s1, string s2) => s1.StartsWith(s2));
}

var query = from p in container.people.AsExpandable()
            where stringFunction.Invoke(p.Name, some_criterion)
            select p;

I believe this fulfils your requirement of

I'd really like to be able to encapsulate the varying behavior (Contains, StartsWith, EndsWith) somehow.

Problem

Problem statement Say I have a query which searches the names of people: ``` var result = (from person in container.people select person) .Where(p => p.Name.Contains(some_criterion) ``` This will be translated to a SQL query containing the following like clause: ``` WHERE NAME LIKE '%some_criterion%' ``` This has some performance implications, as the database is unable to effectively use the index on the name column (index scan v.s. index seek if I'm not mistaken). To remedy this, I can decide to just StartsWith() instead, generating a query using a like clause like: ``` WHERE NAME LIKE 'some_criterion%' ``` Which enables SQL server to use the index seek and delivering performance at the cost of some functionality. I'd like to be able to provide the user with a choice: defaulting the behavior to use StartsWith, but if the user want the 'added flexibility' of searching using Contains(), than that should used. What have I tried I thought this to be trivial and went on and implemented an extension method on string. But of course, LINQ does not accept this and an exception is thrown. Now, of course I can go about and use an if or switch statement and create a query for each of the cases, but I'd much rather solve this 'on a higher level' or more generically. In short: using an if statement to differentiate between use cases isn't feasible due to the complexity of the real-life application. This would lead to alot of repetition and clutter. I'd really like to be able to encapsulate the varying behavior (Contains, StartsWith, EndsWith) somehow. Question Where should I look or what should I look for? Is this a case for composability with IQueryables? I'm quite puzzled!

Original source

Related problems