Я пытаюсь интегрировать функцию поиска в свою таблицу данных в Asp.Net Core. Я загружаю контент динамически с помощью запроса на свой сервер MSSQL. Поскольку содержимое таблицы базы данных со временем будет резко увеличиваться, я бы хотел «предварительно выбрать» результат страницы, применив все фильтры непосредственно к команде sql (вместо того, чтобы использовать AsEnumerable
и делать это на стороне клиента).
Но у меня возникла проблема с полем даты и времени (на самом деле datetime2(7)
). На мой взгляд, я отображаю это значение как «ShortDateFormat <HH:mm:ss>, созданное администратором», например «11.12.2024 02:40:20, созданное администратором».
Теперь я реализовал панель поиска и хотел бы, чтобы запись отображалась, если я наберу в ней «12/11», но этого не происходит.
Для этого я использовал этот запрос:
string searchValue;
string localizedText = null; // Doesn't matter how this is filled for this problem.
IQueryable<Entity> query = Entities.Where(x => x.CreateDate.ToString() + " " + localizedText).ToLower().Contains(searchValue));
К сожалению, похоже, что мой клиент и сервер используют разные форматы даты, поскольку когда я ищу «2024-», запись действительно появляется. Похоже, что метод ToString() не поддерживает здесь параметр формата даты, так как мне преобразовать формат моего сервера в формат, который использует клиент? Однако я не знаю формат клиента во время компиляции, и он должен поддерживать несколько языков, поэтому я не уверен, как я могу это сделать.
Технически я использовал .ToShortDateString
для представления, но, по крайней мере, на моем языке он соответствует формату <ЧЧ:мм:сс>", поэтому теоретически он должен работать. Я отказался от попыток использовать ShortDateFormat для своего запроса, поскольку в результате получается та же ошибка, что и при указании формата в ToString()
, который невозможно перевести.
возможно, стоит попробовать ef.like здесь: stackoverflow.com/questions/45708715/…
@Ralf Нет, мое представление cshtml Asp.Net Core. Мой сайт в основном. Я выполняю запрос (со значением поиска), затем преобразую результат в свой объект JSON с нужным форматом и затем отображаю его. База данных просто передает свои обычные значения моему контроллеру, который затем предпринимает действия по преобразованию.
Тогда зачем вам нужно фильтровать (где) эту сгенерированную строку? Не можете ли вы просто отфильтровать CreateDate как дату и, предположительно, какое-то пользовательское поле, чтобы предотвратить возникновение каких-либо проблем с форматированием? Форматирование — это проблема преобразования чего-либо в строку. Поле даты не имеет этого.
Я думаю, проблема здесь в том, что вы пытаетесь выполнить лексический фильтр/поиск в столбце типа datetime. Я бы рекомендовал разделить GridColumn на столбец CreatedOn (Date(Time)) и столбец CreatedBy (строка), чтобы вы могли работать с соответствующими типами.
я думаю, ОП хочет сделать что-то вроде: select * from sometable where convert(varchar(30), somedatefield, someStyleMatchingClientDate) like '%inputdate%'
. Вероятно, это возможно по тому, зачем работать больше, чем необходимо? Используйте фиксированный формат даты на стороне сервера, например ггггммдд, и измените строку поиска на что-то, что в конечном итоге соответствует этому формату. Небольшое заявление об отказе от ответственности: я не знаю, как выполнить преобразование ггггммдд на стороне EF Core, но это, вероятно, возможно.
@Ralf Ральф, я не совсем понимаю, что ты имеешь в виду. Пользовательский интерфейс показывает что-то вроде 11.12.2024, и, очевидно, если вы наберете «12/» в строке поиска, оно должно отобразиться, но это не так, как оно выглядит в сравнении запросов (на основе использования «2024 -x» формат работает).
Хорошо, вам не интересно, может ли эта цифра 12 означать день, месяц или год или даже является частью имени пользователя? Тогда вы можете просто вызвать ToString с фиксированной культурой. И надеюсь, что все ваши пользователи имеют одинаковое представление о том, как должно выглядеть свидание.
Да, для меня не имеет значения, где находится совпадение в этом преобразованном поле, хотя, очевидно, я должен уважать культуру, которую пользователь использует для точного сравнения, например, «12/12», поскольку текст поиска может работать в en- США, но не в других случаях, а культура клиента должна определять, как следует проводить это сравнение. Использование фиксированного формата не является вариантом, поскольку я ограничен форматом пользовательского интерфейса «ShortDateString + :hh:mm:ss». Если культура клиента — en-US, следует проверить, соответствует ли строка поиска дате (+ дополнительный текст) этой конкретной локализации.
Затем вам нужно каким-то образом получить настройки культуры клиентов и использовать их.
Да, но проблема здесь в этом «использовании». На самом деле я могу получить культуру клиента (включая форматы дат) через CultureInfo. Но я не знаю, как я могу использовать это в своем SQL-запросе, чтобы преобразовать поле даты и времени. Я не могу передать его в DateTime через ToString(), поскольку ToString с параметром не поддерживается EF.
12/11
11 декабря или 12 ноября? Если вы предполагаете, что все пользователи, вводящие 12/11
, всегда будут означать одно или другое, вы можете просто разбить это на части и сказать WHERE MONTH(column) = 12 AND DAY(column) = 11
(или наоборот). В любом случае вы не сможете использовать индекс, но это, по крайней мере, избавит от всей строковой ерунды, которая переполнена проблемами. Даты есть даты, не относитесь к ним как к строкам, потому что не все в мире используют те же строки, что и вы.
Вероятно, вам необходимо использовать встроенную функцию FORMAT из Sql Server. Кажется, это уже не появилось через EF.Functions. Я только что нашел старый пример (для неосновного EF), который показывает, как его получить и использовать. Надеюсь, кто-то здесь знает более современное решение для EF Core (оно должно быть, но я его просто не нашел).
@Ralf Ты спасешь жизнь, большое спасибо. Я заставил его работать с помощью реализации «встроенного FORMAT». Вероятно, в этой реализации тоже есть несколько нюансов, но, насколько я понимаю, она работает так, как я хочу.
Пожалуйста, опубликуйте свое решение в качестве ответа для большей наглядности. Вы также можете принять ответ, и люди смогут проголосовать за него.
@GertArnold Готово (правда, придется подождать день, чтобы принять).
В своем коде переведите выражение фильтра «12/11» в пару дат, которые будут использоваться в запросе. Затем добавьте критерии для Date>=beginDate and Date<endDate
.
Что, если он ищет «2/1» и хочет найти «11.12.2024»? Вот как я понял, почему он хочет этого именно так, как он делает сейчас.
Благодаря Ральфу я нашел встроенный метод FORMAT из SQL и реализацию, которая, похоже, решает мою проблему:
public class AppContext : DbContext
{
[DbFunction(IsBuiltIn = true)]
public static string FORMAT(DateTime value, string formatType, string culture)
=> throw new InvalidOperationException("Do not call this directly");
protected override void OnModelCreating(ModelBuilder builder)
{
builder.HasDbFunction(typeof(AppContext)
.GetRuntimeMethod("FORMAT", [typeof(DateTime), typeof(string), typeof(string)]));
base.OnModelCreating(builder);
}
}
а затем мой запрос:
string culture = CultureInfo.CurrentCulture.Name;
string datePattern = CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern;
Entities.Where(x => (ApplicationContext.FORMAT(x.CreateDate, datePattern, culture) + " " + localizedText).Contains(searchValue);
Вероятно, существует более чистый и лучший способ написать это, но на данный момент этого достаточно.
Возможно, было бы полезно иметь эту функцию базы данных, но учтите, что результат не записываемый. Решение Дэвида таково.
@GertArnold Проблема здесь, как отметил Ральф, заключается в том, что я хотел бы реализовать это как полный поиск, где ввод может находиться в произвольной точке внутри поля. Не говоря уже о том, что мой результат в любом случае не подлежит Саргированию, поскольку я использую .Contains(searchValue) для других моих полей (которые здесь не показаны), что переводится как LIKE %searchValue%, что, насколько я понимаю, тоже не подлежит Саргированию.
Вы говорите «Просмотр», вы имеете в виду представление SqlServer, поэтому в базе данных создается строка «11.12.2024 02:40:20, созданная администратором»?