Implement Case-Insensitive String Comparisons with Dynamic LINQ

You can perform string comparison operations using the Dynamic Linq library by invoking string methods, but by default the string comparisons are case-sensitive, which is generally not desirable when performing dynamic queries. The problem is solvable, but the solution is not immediately obvious, or at least it wasn’t to me. Here is a little sample code and data to illustrate the problem:

namespace ConsoleApplication1
{
    public class Falafel
    {
        public string Name { get; set; }

        public Falafel(string name)
        {
            Name = name;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            List<Falafel> falafels = new List<Falafel>(new[] {
                new Falafel("Lino Tadros"),
                new Falafel("Noel Rice"),
                new Falafel("John Waters"),
                new Falafel("Lance Bullock"),
                new Falafel("Adam Anderson"),
                new Falafel("Mike Dugan"),
                new Falafel("Bary Nusz"),
                new Falafel("Rachel Hagerman"),
                new Falafel("Gary Campbell"),
                new Falafel("Basem Emara"),
                new Falafel("Jonathan Tower"),
                new Falafel("Peter Kinmond"),
                new Falafel("Matt Kurvin"),
                new Falafel("Scott Frolich"),
                new Falafel("Josh Eastburn"),
                new Falafel("Sean Samuel"),
                new Falafel("Jonathan Saad") });

            foreach (Falafel falafel in falafels.AsQueryable<Falafel>().Where("Name.StartsWith(@0)", "A"))
            {
                Console.WriteLine(falafel.Name);
            }

            Console.ReadLine();
        }
    }
}

The output of this program will be “Adam Anderson” as expected. However, if you change the second argument of the dynamic Where method from “A” to “a”, the query will no longer return anything, because the single-argument StartsWith method performs case-sensitive string comparisons. What we want is something like this, but in a Dynamic Linq string:

Name.StartsWith("a", StringComparison.CurrentCultureIgnoreCase)

But if we try that, we will get a ParseError with message “No property or field 'StringComparison' exists in type 'Falafel'”. This is because of the way the Dynamic Linq parser tries to resolve identifiers. It always tries to resolve everything as if it is a member or property of the queryable type. I know of two ways to work around this problem.

The first workaround is simply to add a property to the custom class that returns the StringComparison value you want. For example, you would modify the Falafel class like this:

 public class Falafel
    {
        public StringComparison IgnoreCase
        {
            get { return StringComparison.CurrentCultureIgnoreCase; }
        }

        public string Name { get; set; }

        public Falafel(string name)
        {
            Name = name;
        }
    }

And then reference the new IgnoreCase property in the dynamic query like this:

foreach (Falafel falafel in falafels.AsQueryable<Falafel>().Where("Name.StartsWith(@0, IgnoreCase)", "a"))

This workaround is really only possible when you have access to the queryable type.

The second workaround will work even if you don’t have access to the queryable type. Instead of trying to make the Dynamic Linq parser recognize a string constant inside the query, you can pass the StringComparison value as a parameter, like this:

foreach (Falafel falafel in falafels.AsQueryable<Falafel>().Where("Name.StartsWith(@0, @1)", "a", StringComparison.CurrentCultureIgnoreCase))

This approach is probably the most well-suited for general usage, since it works with both the queryable type and the Dynamic Linq parser as-is with no modifications.

Case-insensitive string comparison with Dynamic Linq can seem difficult or impossible at first thanks to the way that the Dynamic Linq parser resolves references within the string, but with these workarounds, you now have two solutions that you can apply to your own project to get the job done.

comments powered by Disqus

Get weekly updates in your inbox!