I have tested the like function but it is not resulting correct as op stated. So only one option left remains. Which is to create an interceptor and implement custom logic. I have created a sample like below :
public class Suffixes
{
public const string Collate = "--Collate";
}
public class CollationDbCommandInterceptor : DbCommandInterceptor
{
private const string CollateSyntax = " collate turkish_ci_as";
public override InterceptionResult<DbDataReader> ReaderExecuting(DbCommand command, CommandEventData eventData, InterceptionResult<DbDataReader> result)
{
var args = command.Parameters.OfType<DbParameter>()
.Where(t => t.DbType == DbType.String && t.Value.ToString().EndsWith(Suffixes.Collate)).ToList();
if (args.Count <= 0)
return base.ReaderExecuting(command, eventData, result);
foreach (var parameter in args)
{
parameter.Value = parameter.Value.ToString().Replace(Suffixes.Collate, "");
var equality = $"= {parameter.ParameterName}";
var ixs = AllIndexesOf(command.CommandText, equality);
#pragma warning disable CA2100 // Review SQL queries for security vulnerabilities
foreach (var eq in ixs)
{
command.CommandText = command.CommandText.Insert(eq+equality.Length,CollateSyntax);
}
#pragma warning restore CA2100 // Review SQL queries for security vulnerabilities
}
return base.ReaderExecuting(command, eventData, result);
}
private static IEnumerable<int> AllIndexesOf(string str, string value)
{
if (string.IsNullOrEmpty(value))
throw new ArgumentException("the string to find may not be empty", nameof(value));
var indexes = new List<int>();
for (var index = 0; ; index += value.Length)
{
index = str.IndexOf(value, index);
if (index == -1)
return indexes;
indexes.Insert(0,index);
}
}
}
Configuration :
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
....
optionsBuilder.AddInterceptors(new CollationDbCommandInterceptor());
....
}
}
Usage :
var kadayif = $"kadayıf{Suffixes.Collate}";
var william = $"Wİlliam{Suffixes.Collate}";
var auths = ctx.Authors.Where(t => t.FirstName == william ||t.LastName == kadayif).ToList();
// returns William Shakespeare and Abuzer Kadayıf
The logic is to create an interceptor that seeks a specific suffix in sql parameters passed in the query. Injects query specific collation in to the final sql command text. I tried to cover some advanced scenarios like parameter reuse. It may require more improvements.
Please note that this example is for Entity Framework Core 3.0 which is the version that interceptors introduced. Interception in earlier ef core versions is a bit trick. You can refer to this link for further information.