Я не уверен в правильности формата использования строки и даты в качестве переменных в динамическом IQueryable
. С числами, даже если они передаются как строки, все работает корректно. Однако если я использую строки или даты, запрос прерывается без ошибок; просто зависает приложение. Я уверен, что мне не хватает кавычек, но я не могу правильно определить формат.
Это мой код:
string userFilter = string.Empty;
string var1 = "3";
string var2 = "54";
string var3 = "Doe, John";
DateTime var4 = DateTime.Now();
IQueryable<MyClass> query = await _context.Table.GetData();
if (!string.IsNullOrEmpty(var1))
{
userFilter = " column1 == " + var1 + " &&";
}; //This works
if (!string.IsNullOrEmpty(var2))
{
userFilter = userFilter + " column2 == " + var2 + " &&";
}; //This works
if (!string.IsNullOrEmpty(var3))
{
userFilter = userFilter + " column3 == \"" + var3 + "\" &&";
}; //Works
if (!string.IsNullOrEmpty(var4))
{
userFilter = userFilter + " column4 == " + var4 + " &&";
}; //Doesn't work
userFilter = userFilter.TrimEnd('&');
query = query.Where(userFilter);
var myData = query.ToList();
Первые два «если» работают правильно, или любые другие с числами в виде строк, но реальные строки или даты — нет. Что мне не хватает?
Спасибо!
@Dai Честно говоря, мне проще сделать это так. Я понял, как обращаться со строками, но мне все еще нужна помощь с датами.
Я мог бы предложить использовать yourDateTimeValue.ToString( "o", CultureInfo.InvariantCulture )
- строка формата "o"
предназначена для «туда и обратно», что означает отсутствие потери точности и всегда преобразуется в формат ISO 8601 / RFC 3339, который является однозначным и большинство систем принимают «как есть» - я предполагаю, что вы Однако понадобятся разделительные кавычки или что-то подобное.
Пожалуйста, поделитесь, какую именно библиотеку Linq/IQueryable вы используете, в которой есть эти методы Linq на основе String
— извините, я ее не узнаю.
@Dai, используя System.Linq.Dynamic.Core;
@Дай, изначально это было существо Редмонда weblogs.asp.net/scottgu/…
@SvyatlavDanyliv Я ем свои слова :)
Если вы посмотрите на значение userFilter, вы увидите, что проблема с var4 заключается в том, что вы создаете строку запроса, содержащую строку даты без кавычек. Но, как говорит @Dai, вам лучше использовать формат даты, не зависящий от культуры. См. рабочий пример dotnetfiddle.net/AFPWru, и я также включил тот же запрос с использованием динамического linq с параметрами (что лучше, но по-прежнему создает аналогичный sql), и если вы знаете имена столбцов, тот же запрос без использование динамического linq, что еще лучше, поскольку оно генерирует лучший sql.
@sgmoore Первое, что я попробовал, прежде чем опубликовать свой вопрос, — это использовать \"" + ... + "\". Я также пробовал использовать параметры. В обоих случаях я получаю «Номер ошибки: 241, Состояние: 1, Класс: 16». Итак, я проверяю, как выглядит генерируемый SQL, и выглядит следующим образом: SELECT * From MyTable AS [d] WHERE [d].[MyDate] = '2024-07-01T00:00:00.0000000' Я проверил в базе данных - это не нравится такой формат даты. Но по вашим рекомендациям мне удалось доработать код и заставить его работать. Спасибо.
Библиотека System.Linq.Dynamic.Core
использует собственный синтаксис для значений DateTime, который напоминает вызовы ctor, например:
context.Customers.Where("DateTimeProperty >= DateTime(2024,8,16,18,33,0)").ToList();
...но лучше использовать параметры вида @<n>
, где <n>
— целое число:
DateTime now = DateTime.UtcNow;
context.Customers.Where("DateTimeProperty >= @0", now).ToList();
// Protip: For greater readability, define this extension method:
public static class StringExtensions
{
public static Boolean IsSet( [NotNullWhen(true)] this String? s ) => !String.IsNullOrWhiteSpace( s );
}
//
String var1 = "3";
String var2 = "54";
String var3 = "Doe, John";
DateTime var4 = DateTime.UtcNow();
IQueryable<MyClass> query = await _context.Table.GetData();
////////
if ( var1.IsSet() ) query = query.Where( "column1 == @0", var1 );
if ( var2.IsSet() ) query = query.Where( "column2 == @0", var2 );
if ( var3.IsSet() ) query = query.Where( "column3 == @0", var3 );
query = query.Where( "column4 == @0", var4 );
////////
var myData = query.ToList();
Приведенные выше query = query.Where(...)
утверждения будут объединены в AND
термины. А если вам нужна OR
логика, вы не можете использовать PredicateBuilder.Or
, потому что это не Func<T,Boolean>
или Expression<Func<>>
методы, но мы можем взломать ее с помощью .Union:
(Непроверено, YMMV)
String var1 = "3";
String var2 = "54";
String var3 = "Doe, John";
DateTime var4 = DateTime.UtcNow();
IQueryable<MyClass> q = await _context.Table.GetData();
IQueryable<MyClass> u = q.Where( "1 = 0" ); // <-- This always-false term makes it less-awkward.
////////
if ( var1.IsSet() ) u = u.Union( q.Where( "column1 == @0", var1 ) );
if ( var2.IsSet() ) u = u.Union( q.Where( "column2 == @0", var2 ) );
if ( var3.IsSet() ) u = u.Union( q.Where( "column3 == @0", var3 ) );
u = u.Union( q.Where( "column4 == @0", var4 ) );
////////
var myData = u.ToList();
Привет @Dai Спасибо, что нашли время написать код. Я понял, как выполнять запросы с помощью Ling Dynamic без зависания приложения, поэтому оно компилируется и выполняется; однако я получаю сообщение об ошибке. Это та же ошибка, которую я получаю с вашим кодом: Номер ошибки: 241, Состояние: 1, Класс: 16. Это ошибка преобразования даты. Я пробовал отформатировать дату 50 различными способами, но приложение снова зависает без ошибки возврата или продолжает возвращать ту же ошибку.
Есть ли причина, по которой вы не можете использовать строго типизированные методы Linq на основе
Expression<Func<>>
? Я не понимаю, как строковые выражения DynamicLinq помогут вам здесь...