#c# #sql #sql-server #entity-framework
#c# #sql #sql-сервер #entity-framework
Вопрос:
Давайте предположим, что у меня есть база данных SQL Server и таблица, которая выглядит как:
Id int NOT NULL,
Date date NOT NULL
У меня есть соответствующая модель entity framework:
public class Bundle
{
public int Id {get; set;}
public DateTime Date {get; set;}
}
Пользователь может ввести строку, которая может быть любой. Мне нужно найти все элементы, где дата или любая часть даты содержит строку, введенную пользователем. Итак, в принципе, мне нужно выполнить запрос:
SELECT Id, Date
FROM Bundles
WHERE Date LIKE '%user_query_here%'
Моя первая попытка была
query.Where(b => b.Date.ToShortDateString().Contains(filter.Date))
Это вызывает исключение NotSupportedException, поэтому я попробовал это:
query.Where(b => Convert.ToString(b.Date).Contains(filter.Date));
Пожалуйста, обратите внимание, что фильтр.Дата — это строка. Это не структура DateTime.
Это также приводит к возникновению исключения. Итак, мой вопрос в том, как выполнить запрос, написанный выше?
PS: Я не могу выполнить фильтрацию в памяти, в этой таблице много тысяч строк.
Комментарии:
1. Вы уверены в своем требовании? Мне кажется, что полагаться на строковое представление даты действительно опасно. Что, если культура между клиентом и сервером отличается?
2. Да, я полностью уверен. И я не боюсь проблем, которые могут возникнуть, если культура на сервере и клиенте отличается.
3. Вы знаете, что это будет невероятно медленно, не так ли, поскольку он не будет использовать индексы? Если бы у вас была таблица календаря, вы могли бы запустить поиск по дате по ней (гораздо меньшая таблица, с разделенными столбцами в индексах тоже), которые затем можно было бы объединить как часть обычного запроса диапазона …. но я не уверен, как с этим справиться в Entity Framework.
4. Да, я знаю об индексах. Это не имеет большого значения, потому что у меня нет индекса в этом столбце.
Ответ №1:
К сожалению, нет простого способа преобразовать datetime в строку с помощью l2e.
Вы можете использовать некоторые методы SqlFunctions
SqlFunctions.DatePart
вернет значение int, представляющее часть даты (например, год, месяц, день).
и
SqlFunctions.StringConvert
может помочь вам преобразовать значение int в строку (сначала преобразовав его в double), которое затем можно объединить.
Что-то вроде
.Where(b => (SqlFunctions.StringConvert((double)SqlFunctions.DatePart("y", b))
SqlFunctions.StringConvert((double)SqlFunctions.DatePart("m", b))
//etc.
).Contains(filter.Date)
конечно, это нечитаемо и действительно не подходит для индексации.
(Намного) более простым и чистым способом, если вы работаете с sql Server, было бы создать и использовать вычисляемый столбец.
Вы можете создать его таким образом (в Google можно найти, как это сделать правильно, если вы сначала используете Code и миграции)
alter table add StringDate as convert(varchar, [Date], 112)//or another format, this will be yyyymmdd
Если вы сначала используете код, вам придется пометить свойство атрибутом
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
Тогда вы сможете сделать
.Where(b => b.StringDate.Contains(filter.Date))
Комментарии:
1. Большое спасибо за решение. Я использовал решение для вычисляемых столбцов.