Efcore: How to use case-insensitive query with Sqlite provider ?

Created on 24 Mar 2018  路  12Comments  路  Source: dotnet/efcore

I'm not sure if I remember wrongly,
I see the COLLATE NOCASE append in the sql query very long time ago (may be not COLLATE NOCASE,but something else , all I remember is my query is case insensitive),

but recently I use Sqlite again , and it is case sensitive , and I can not compare an "Email" filed with x.Email == myvariable

closed-question

Most helpful comment

Also note, SQLite only performs case-insensitive comparisons of ASCII characters. Override the default to include all Unicode characters:

var connection = (SqliteConnection)db.Database.GetDbConnection();
connection.CreateCollation("NOCASE", (x, y) => string.Compare(x, y, ignoreCase: true));

All 12 comments

Some users have been successful by configuring the property like this: (although it's certainly not how the API was intended to be used)

modelBuilder.Entity<X>().Property(x => x.Email).HasColumnType("TEXT COLLATE NOCASE");

Currently, the only way to do it per-query (not configuring the column) is by using raw SQL:

db.X.FromSql($"SELECT * FROM X WHERE Email = {myvariable} COLLATE NOCASE").Where(...);

Also note, SQLite only performs case-insensitive comparisons of ASCII characters. Override the default to include all Unicode characters:

var connection = (SqliteConnection)db.Database.GetDbConnection();
connection.CreateCollation("NOCASE", (x, y) => string.Compare(x, y, ignoreCase: true));

@bricelam thanks a lot,
but, I don't understand your last code, what is SqliteConnection.CreateCollation() ?
and may I ask , does Sqlite "case-insensitive" in EF 1.x ?

The last code listing uses SQLite's ADO.NET APIs (the layer beneath EF Core) to replace SQLite's built-in NOCASE comparison with .NET's more complete implementation. (using pure unicorn magic 馃)

Yes, my first two comments also apply to EF Core 1.x.

@bricelam Thanks again.

to replace SQLite's built-in NOCASE comparison with .NET's more complete implementation.

Is that because Sqlite's ADO.Net provider is also the database engine so it can do that ? otherwise AFAK doing comparison in "client" side is pointless .

SQLite is an in-process database. The snippet above works by passing a function pointer to SQLite that it can use to invoke the lambda. So technically, it is happening "on the server".

This is different from EF's client-evaluated queries where extra data may be retrieved from the server so additional processing can be done on the client before returning the final result set.

I walk through the differences between client-eval and passing pointers to SQLite in my SQLite & EF Core: UDF all the things! post.

@bricelam Can this be closed?

Yep. @John0King feel free to continue the conversation here even though the issue is closed.

Quick question, when should I execute the code:

var connection = (SqliteConnection)db.Database.GetDbConnection();
connection.CreateCollation("NOCASE", (x, y) => string.Compare(x, y, ignoreCase: true));

And, is it enough or I also need to use the .HasColumnType("TEXT COLLATE NOCASE"); trick?

If I do it in the OnModelCreating I get a CreateCollation can only be called when the connection is open. execption

Was this page helpful?
0 / 5 - 0 ratings