Найти в Дзене

LINQ. NHibernate. Регистронезависимый поиск по строке

Задача: проверить наличие записи по строке Не оптимальные пути DataStore.GetAll<Foo>().Any(x => x.Code == "123"); Генерируемый SQL: select * from foo where code=$1 limit 1 Проблемы этого решения: DataStore.GetAll<Foo>().Any(x => x.Code.ToLower() == "123"); Генерируемый SQL: select * from foo where lower(code)=$1 limit 1 Проблемы этого решения: Оптимальные пути DataStore.GetAll<Foo>().Select(x => x.Code).AnyAsync(x => SqlMethods.Like(x.ToLower(), "123")); select code from foo where lower(code) like $1 limit 1 DataStore.GetAll<Foo>().Count(x => SqlMethods.Like(x.Code.ToLower(), "123")) > 0; select count(*) from foo where lower(code) like $1 Выборка count(*) плохо себя показывает на больших таблицах DataStore.GetAll<Foo>().Count(x => x.Code.Equals("123", StringComparison.OrdinalIgnoreCase)) > 0; select count(*) from foo where lower(code)=lower($1) Выборка count(*) плохо себя показывает на больших таблицах DataStore.GetAll<Foo>().Count(x => x.Code.ToLower() == "123") > 0; select count(*
Оглавление

Задача: проверить наличие записи по строке

Не оптимальные пути

DataStore.GetAll<Foo>().Any(x => x.Code == "123");

Генерируемый SQL: select * from foo where code=$1 limit 1

Проблемы этого решения:

  • расходы на получение всей записи с маппингом в объект памяти
  • регистрозависимый поиск по полю code (обычно это не нужно)
DataStore.GetAll<Foo>().Any(x => x.Code.ToLower() == "123");

Генерируемый SQL: select * from foo where lower(code)=$1 limit 1

Проблемы этого решения:

  • расходы на получение всей записи с маппингом в объект памяти

Оптимальные пути

DataStore.GetAll<Foo>().Select(x => x.Code).AnyAsync(x => SqlMethods.Like(x.ToLower(), "123"));

select code from foo where lower(code) like $1 limit 1

DataStore.GetAll<Foo>().Count(x => SqlMethods.Like(x.Code.ToLower(), "123")) > 0;

select count(*) from foo where lower(code) like $1

Выборка count(*) плохо себя показывает на больших таблицах

DataStore.GetAll<Foo>().Count(x => x.Code.Equals("123", StringComparison.OrdinalIgnoreCase)) > 0;

select count(*) from foo where lower(code)=lower($1)

Выборка count(*) плохо себя показывает на больших таблицах

DataStore.GetAll<Foo>().Count(x => x.Code.ToLower() == "123") > 0;

select count(*) from foo where lower(code)=$1

Выборка count(*) плохо себя показывает на больших таблицах

DataStore.GetAll<Foo>().Where(x => x.Code.Equals("123", StringComparison.OrdinalIgnoreCase)).Select(x => 1).FirstOrDefaultAsync() == 1;

select 1 from foo where lower(code)=lower($1)

Лучше себя показывает на больших таблицах (если запись не в конце таблицы), хорошо чувствует себя при наличии индекса по Code

Для удобства:

public static async Task<bool> ExistsAsync<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate, CancellationToken cancellationToken = default)
{ return await source.Where(predicate).Select(x => 1).FirstOrDefaultAsync(cancellationToken) == 1; }