简体   繁体   中英

Case-insensitive “contains” in Linq

I have a mvc project which I use linq in it. In my database there is some records, for example "Someth ing","SOmeTH ing","someTh ing","SOMETH ING","someTH ING"

I want to do this:

SELECT * FROM dbo.doc_dt_records WHERE name LIKE '%' + @records.Name + '%'

However if I run this code, list.Count returns 0. What should I do?

    records.Name = "someth ing"; //for example
    var rec = db.Records.ToList();
         var lists = rec.Where(p => p.Name.Contains(records.Name)).ToList();
if (lists.Count > 0)
{
    // do sthng
}

Thanks for your helps...

the easy way is to use ToLower() method

var lists = rec.Where(p => p.Name.ToLower().Contains(records.Name.ToLower())).ToList();

a better solution (based on this post: Case insensitive 'Contains(string)' )

 var lists = rec.Where(p => 
             CultureInfo.CurrentCulture.CompareInfo.IndexOf
             (p.Name, records.Name, CompareOptions.IgnoreCase) >= 0).ToList();

That is totally not a LINQ issue.

Case sensitiivty on the generated SQL depends on the collation relevant for the table. Which in your case likely is case insensitive.

You would get the same result from any SQL you emit.

use IndexOf and StringComparison.OrdinalIgnoreCase :

p.Name.IndexOf(records.Name, StringComparison.OrdinalIgnoreCase) >= 0;

You can create an extension function like this:

public static bool Contains(this string src, string toCheck, StringComparison comp)
{
    return src.IndexOf(toCheck, comp) >= 0;
}

To my understanding, this question does not have an unambiguous answer. The matter is that the best way of doing this depends on details which aren't provided in the question. For instance, what exact ORM do you use and what precise DB server you are connected to. For example, if you use Entity Framework against MS SQL Server, you better do not touch your LINQ expression at all. All you need to do is to set the case-insensitive collation on the database/table/column you compare your string with. That will do the trick much better than any change of your LINQ expression. The matter is that when LINQ is translated to SQL, it better be the straight comparison of the column having case-insensitive collation to your string than anything else. Just because it usually works quicker and it is the natural way to do the trick. You do not want the final query to be something like:

SELECT  *
  FROM  AspNetUsers     U
 WHERE  UPPER(U.Name)   LIKE '%SOMETHING%';

It is much better to come up with something like:

SELECT  *
  FROM  AspNetUsers U
 WHERE  U.Name      LIKE '%SOMETHING%';

But with a case-insensitive collation of [Name] column. The difference is that if you have let's say index containing [Name] column, the second query might use it, the first one would do the full scan of the table anyway.

So if let's say records references to DBSet<T> and the record is just one object of type T . You code would be like this:

var lists = records.Where(p => p.Name.Contains(record.Name)).ToList();

And you do the rest on SQL-server. Or if all you need to know is there any value in the list and do not need these values, it would be even better to do like this:

if (records.Any(p => p.Name.Contains(record.Name)))
{
    // do something
}

Generally speaking, if you use any sort of ORM connected to any sort of SQL server, you better do case-insensitivity by setting up appropriate parameters of your server/database/table/column. And only if it is impossible or by far too expensive, you consider other possibilities. Otherwise, you might bang into some unexpected and very unpleasant behaviour. For instance, Entity Framework Core 2.x if it cannot translate your LINQ expression straightway into SQL query, is doing different tricks replacing server-side operations with client-side ones. So you can end up with a solution which fetches all data from the table to the client and filter it there. It might be quite a problem if your table is big enough.

As for the situation when LINQ query is processed locally, there are a lot of ways to do the trick. My favourite one is the next:

        var lists = records.Where(p => p.Name
            .Contains(record.Name, StringComparison.InvariantCultureIgnoreCase))
            .ToList();

try this

var lists = rec.Where(p => String.Equals(p.Name,records.Name,StringComparison.OrdinalIgnoreCase)).ToList();

refer here for documentation

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM