Подтвердить что ты не робот

LINQ: добавление предложения where только тогда, когда значение не равно нулю

Я знаю, что типичный способ таков:

IQueryable query = from staff in dataContext.Staffs;
if(name1 != null)
{
     query = from staff in query where (staff.name == name1);
}

Однако из программы, которую мы взяли у других разработчиков, мы увидели такой код:

IQueryable query = from staff in dataContext.Staffs;
query = from staff in query where (name1 == null || staff.name == name1);

Если это нормальный оператор SQL, я бы определенно сказал, что второй - это плохая практика. Поскольку он добавляет бессмысленное предложение where к запросу, когда name1 имеет значение null.

Но я новичок в LINQ, поэтому я не уверен, что LINQ отличается?

4b9b3361

Ответ 1

вы можете написать его как

IQueryable query = from staff in dataContext.Staffs;
query = from staff in query where (name1 != null && staff.name == name1);

Таким образом, вторая часть вашего условия не будет оцениваться, если ваше первое условие оценивается как false

Update:
если вы пишете

IQueryable query = from staff in dataContext.Staffs;
    query = from staff in query where (name1 == null || staff.name == name1);

и name1 является нулевой второй частью вашего условия, не будет оцениваться, так как или условие требует только одного условия для возврата true

plz см. ссылку для более подробной информации

Ответ 2

Часто такая вещь кажется более гладкой для написания, используя свободный синтаксис, а не синтаксис запроса.

например.

IQueryable query = dataContext.Staffs;
if(name1 != null)
{
     query = query.Where(x => x.name == name1);
}

Итак, если name1 равно null, вы просто не выполняете вызов Where(). Если у вас есть несколько разных фильтров, все из которых могут потребоваться или не потребоваться, и, возможно, различные разные порядки сортировки, я считаю, что это становится намного более управляемым.

Изменить для alex: Хорошо, я отвечал на вопрос о добавлении предложения where, только когда значение не равно null. В ответ на другую часть вопроса я попробовал это с Entity Framework 4, чтобы увидеть, что SQL, который создал LINQ. Вы делаете это, бросая query в ObjectQuery и вызывая .ToTraceString(). Результаты заключались в том, что предложение WHERE вышло следующим образом:

WHERE @p__linq__0 IS NULL OR [Extent1].[name] = @p__linq__1

Итак, да, это классический плохой SQL, если у вас есть индекс в столбце name, не ожидайте его использования.

Изменить # 2: Пробовал это снова, используя LINQ to SQL, а не Entity Framework, с довольно разными результатами. На этот раз попытка запроса с name1 быть нулевым, вообще говоря, не имеет понятия WHERE, как вы могли бы надеяться; попробовав его с name1, являющимся "a", привел к простому WHERE [t0].[name] = @p0 и @p0, отправленному как "a". Таким образом, инфраструктура Entity Framework делает не оптимизацию. Это немного беспокоит.

Ответ 3

LINQ отличается некоторыми другими причинами (не по этим причинам), LINQ - это способ получить данные в "Быстрее пути" с кодом littel и очистить трек, насколько это возможно, существует множество преимуществ LINQ:

  • Упрощает преобразование данных в объекты. Я уверен, что вы слышали, что термин "Impedence Mismatch" используется довольно часто, что означает, что LINQ уменьшает объем работы, которую вы должны выполнять, для перевода между объектно-ориентированным кодом и парадигмами данных, такими как иерархические, плоские файлы, сообщения, реляционные и многое другое. Он не устраняет "несоответствие импеданса", потому что вы все еще должны рассуждать о своих данных в своей нативной форме, но мост оттуда к нему (IMO) намного короче.

  • Общий синтаксис для всех данных. После изучения синтаксиса запроса вы можете использовать его с любым поставщиком LINQ. Я думаю, что это гораздо лучшая парадигма развития, чем Вавилонская башня, которая за эти годы выросла с технологиями доступа к данным. Конечно, у каждого провайдера LINQ есть уникальные нюансы, которые необходимы, но основной подход и синтаксис запроса одинаковы.

  • Сильно напечатанный код. Синтаксис запроса С# (или VB.NET) является частью языка, и вы кодируете типы С#, которые преобразуются во что-то, что понимает провайдер. Это означает, что вы получаете производительность, заключающуюся в том, что ваш компилятор обнаруживает ошибки ранее в жизненном цикле разработки, чем в других местах. Конечно, многие ошибки в сохраненном синтаксисе proc будут генерировать ошибки при сохранении, но LINQ более общий, чем SQL Server. Вы должны думать обо всех других типах источников данных, которые генерируют ошибки времени выполнения, потому что их запросы формируются с помощью строк или какого-либо другого слабо типизированного механизма.

  • Интеграция провайдера. Сближение источников данных очень просто. Например, вы можете использовать LINQ для объектов, LINQ to SQL и LINQ to XML вместе для некоторых очень сложных сценариев. Я думаю, что это очень элегантно.

  • Сокращение работы. До LINQ я потратил много времени на создание DAL, но теперь мой DataContext - это DAL. Я также использовал OPF, но теперь у меня есть LINQ, который поставляется с несколькими провайдерами в коробке и многими другими сторонними поставщиками, что дает мне преимущества от моих предыдущих пунктов. Я могу настроить LINQ to SQL DataContext через минуту (так же быстро, как мой компьютер и IDE могут не отставать).

  • Производительность в общем случае не становится проблемой. SQL Server оптимизирует запросы в наши дни, как и хранимые процессы. Конечно, все еще есть случаи, когда хранимые процедуры необходимы для повышения производительности. Например, я нашел умнее использовать хранимую процедуру, когда у меня было несколько взаимодействий между таблицами с дополнительной логикой внутри транзакции. Накладные расходы на связь, связанные с попыткой выполнить одну и ту же задачу в коде, помимо того, что DTC участвует в распределенной транзакции, сделали выбор для хранимой процедуры более привлекательной. Тем не менее, для запроса, который выполняется в одном из операторов, LINQ является моим предпочтительным выбором, потому что даже при небольшом усилении производительности от хранимой процедуры преимущества в предыдущих точках (IMO) несут больше веса.

  • Встроенная система безопасности. Одной из причин, по которой я предпочитал хранить procs до LINQ, было то, что они принудительно использовали параметры, помогая уменьшить атаки SQL-инъекций. LINQ to SQL уже параметризует ввод, который так же безопасен.

  • LINQ является декларативным. Большое внимание уделяется работе с LINQ to XML или LINQ to SQL, но LINQ to Objects невероятно мощным. Типичным примером LINQ to Objects является чтение элементов из строки []. Однако это лишь небольшой пример. Если вы думаете обо всех коллекциях IEnumerable (вы также можете запросить IEnumerable), с которыми вы работаете каждый день, возможностей здесь много. то есть поиск элемента управления ListBox ASP.NET для выбранных элементов, выполнение операций набора (например, Union) в двух коллекциях или повторение с помощью списка и запуск лямбда в файле ForEach каждого элемента. Как только вы начнете думать в LINQ, который носит декларативный характер, вы можете найти множество своих задач более простым и интуитивным, чем настоятельные методы, которые вы используете сегодня.

Вероятно, я мог бы продолжить, но мне лучше остановиться. Надеемся, что это обеспечит более позитивное представление о том, как вы могли бы быть более продуктивным с LINQ и, возможно, рассматривать его как полезную технологию с более широкой точки зрения.

Ответ 4

Лучший способ сделать это - создать себе метод расширения, который будет принимать условный оператор и выражение where. Если условие истинно, то оно будет использовать выражение where else, которое оно не будет использовать. Это может резко очистить ваш код, устраняя необходимость в операторах if.

public static class LinqExtensions
{
    public static IQueryable<T> WhereIf<T>(this IQueryable<T> query, bool condition, Expression<Func<T, bool>> whereClause)
    {
        if (condition)
        {
            return query.Where(whereClause);
        }
        return query;
    }
}

Теперь вы можете написать свой код следующим образом:

IQueryable<Staffs> query = dataContext.Staffs.AsQueryable().WhereIf(name1 != null, x => x.Name == name1);

Ответ 5

Мне нравится использовать выражение например.

    Expression<Func<Persons, bool>> expresionFinal = c => c.Active == true;

    if (DateBirth.HasValue)
                {
                    Expression<Func<Persons, bool>> expresionDate = c => (EntityFunctions.TruncateTime(c.DateBirth) == DateBirth);
                    expresionFinal = PredicateBuilder.And(expresionFinal, expresionDate);
                }

IQueryable query = dataContext.Persons;
 query = query.Where(expresionFinal);

Ответ 6

Нет, я не согласен с тобой. здесь вы просто дали простую логику

if(name1 != null)
// do your stuff

но что произойдет, если вы сделаете что-то другое с именем1, имеющим нулевое значение.!! Хорошо, теперь рассмотрим эту ситуацию. В этом примере показано, как обрабатывать возможные значения NULL в коллекциях источников. Коллекция объектов, такая как IEnumerable<T>, может содержать элементы, значение которых равно null. Если исходная коллекция имеет значение null или содержит элемент, значение которого равно null, и ваш запрос не обрабатывает нулевые значения, при выполнении запроса будет выбрано NullReferenceException.

Возможно, это может быть проблемой...

Ответ 7

Я видел этот шаблон в стандартном SQL, и кажется полезным, если у вас есть несколько параметров, которые могут быть NULL. Например:

SELECT * FROM People WHERE ( @FirstName IS NULL OR FirstName = @FirstName )
                       AND ( @LastName IS NULL OR LastName = @LastName )

Если вы видите это в LINQ, возможно, они просто слепо перевели свои старые SQL-запросы.

Ответ 8

Итак, я попробовал метод расширения .Where(..., x => ...), указанный здесь как ответ, но он не работает против Entity Framework, поскольку Linq To Entities не знает, как перевести его в TSQL.

Итак, вот мое решение, получившее мой Func on:

Expression<Func<SomeEfPoco, bool>> columnBeingFilteredPredicate = x => true; // Default expression to just say yes
if (!string.IsNullOrWhiteSpace(someColumnBeingFilteredValue))
{
    columnBeingFilteredPredicate = x => x.someColumnBeingFiltered == someColumnBeingFilteredValue;
}

_context.SomeEfPocos.Where(x => ..... &&
            ..... &&
            ..... &&)
.Where(columnBeingFilteredPredicate);

someColumnBeingFilteredValue В моем случае это строковый параметр для метода инкапсуляции со значением по умолчанию NULL.

Ответ 9

Для EF Core я разбил это следующим образом:

IQueryable<Partners> recs = contextApi.Partners;
if (status != -1)
{
   recs = recs.Where(i => i.Status == status);
}
recs = recs.OrderBy(i => i.Status).ThenBy(i => i.CompanyName);
foreach (var rec in recs)
{
}

Я должен был быть явным с моей типизацией вместо того, чтобы полагаться на var.