|| (или) оператор в Linq с C#

Книга не имеет атрибута order_by, ее менеджер имеет

Так что вам нужно

Book.objects.order_by
12
задан harriyott 22 November 2012 в 15:36
поделиться

6 ответов

Прочитайте эту документацию , в которой объясняется, как linq и c # могут испытывать разъединение.

Поскольку ожидается, что выражения Linq будут сокращены до что-то отличное от простых методов, вы можете обнаружить, что этот код ломается, если позже он используется в некотором контексте, отличном от Linq to Objects.

Тем не менее,

String.IsNullOrEmpty(fromname) || 
(   !String.IsNullOrEmpty(fromname) && 
    msg.FromName.ToLower().Contains(fromname.ToLower())
)

неправильно сформирован, поскольку он действительно должен быть

String.IsNullOrEmpty(fromname) || 
msg.FromName.ToLower().Contains(fromname.ToLower())

, что делает его красивым и понятным что вы полагаетесь на msg и msg.FromName, чтобы они также были ненулевыми.

Чтобы упростить вашу жизнь в c #, вы можете добавить следующий метод расширения строки

public static class ExtensionMethods
{
    public static bool Contains(
        this string self, string value, StringComparison comparison)
    {
        return self.IndexOf(value, comparison) >= 0;
    }

    public static bool ContainsOrNull(
        this string self, string value, StringComparison comparison)
    {
        if (value == null)
            return false;
        return self.IndexOf(value, comparison) >= 0;
    }
}

Затем используйте:

var messages = (from msg in dc.MessageItems
where  msg.FromName.ContainsOrNull(
    fromname, StringComparison.InvariantCultureIgnoreCase)
select msg);

Однако это не проблема. Проблема заключается в том, что аспекты системы Linq to SQL пытаются использовать значение fromname для создания запроса , который отправляется на сервер.

Поскольку fromname является переменной, механизм трансляции отключается и выполняет то, что от него требуется (создавая строчное представление fromname , даже если оно пустое, что вызывает исключение) ).

в этом случае вы можете либо сделать то, что вы уже обнаружили: сохранить запрос как есть, но убедитесь, что вы всегда можете создать ненулевое значение fromname с желаемым поведением, даже если оно пустое.

Возможно, лучше было бы:

IEnumerable<MessageItem> results;
if (string.IsNullOrEmpty(fromname))
{ 
    results = from msg in dc.MessageItems 
    select msg;    
}
else
{
    results = from msg in dc.MessageItems 
    where msg.FromName.ToLower().Contains(fromname) 
    select msg;    
}

Это не так здорово, поскольку запрос содержал другие ограничения и, таким образом, вызывал больше дублирования, но для простого запроса фактически должен привести к более читаемому / поддерживаемому коду. Это неприятно, если вы полагаетесь на анонимные типы, но, надеюсь, это не проблема для вас.

в этом случае вы можете либо сделать то, что вы уже обнаружили: сохранить запрос как есть, но убедитесь, что вы всегда можете создать ненулевое значение fromname с желаемым поведением, даже если оно пустое.

Возможно, лучше будет :

IEnumerable<MessageItem> results;
if (string.IsNullOrEmpty(fromname))
{ 
    results = from msg in dc.MessageItems 
    select msg;    
}
else
{
    results = from msg in dc.MessageItems 
    where msg.FromName.ToLower().Contains(fromname) 
    select msg;    
}

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

в этом случае вы можете либо сделать то, что вы уже обнаружили: сохранить запрос как есть, но убедитесь, что вы всегда можете создать ненулевое значение fromname с желаемым поведением, даже если оно пустое.

Возможно, лучше будет :

IEnumerable<MessageItem> results;
if (string.IsNullOrEmpty(fromname))
{ 
    results = from msg in dc.MessageItems 
    select msg;    
}
else
{
    results = from msg in dc.MessageItems 
    where msg.FromName.ToLower().Contains(fromname) 
    select msg;    
}

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

IEnumerable<MessageItem> results;
if (string.IsNullOrEmpty(fromname))
{ 
    results = from msg in dc.MessageItems 
    select msg;    
}
else
{
    results = from msg in dc.MessageItems 
    where msg.FromName.ToLower().Contains(fromname) 
    select msg;    
}

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

IEnumerable<MessageItem> results;
if (string.IsNullOrEmpty(fromname))
{ 
    results = from msg in dc.MessageItems 
    select msg;    
}
else
{
    results = from msg in dc.MessageItems 
    where msg.FromName.ToLower().Contains(fromname) 
    select msg;    
}

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

14
ответ дан 2 December 2019 в 05:55
поделиться

Хорошо. Я нашел решение .

Я изменил оскорбительную строку на:

where (String.IsNullOrEmpty(fromemail)  || (msg.FromEmail.ToLower().Contains((fromemail ?? String.Empty).ToLower())))

Это работает, но похоже на взлом. Я уверен, что если первое выражение верно, второе не должно оцениваться.

Было бы здорово, если бы кто-то мог подтвердить или опровергнуть это для меня ...

Или, если у кого-то есть лучшее решение, пожалуйста, дайте мне знать !!!

5
ответ дан 2 December 2019 в 05:55
поделиться

Если вы используете LINQ to SQL, вы не можете ожидать того же C # короткое замыкание в SQL Server. См. этот вопрос о предложениях короткого замыкания WHERE (или их отсутствия) в SQL Server.

Кроме того, как я упоминал в комментарии, я не думаю, что вы получаете это исключение в LINQ to SQL, потому что:

  1. Method String. IsNullOrEmpty (String) не поддерживает перевод на SQL, поэтому его нельзя использовать в LINQ to SQL.
  2. Вы не получите исключение NullReferenceException. Это управляемое исключение, это может произойти только на стороне клиента, а не в SQL Server.

Вы уверены, что это не проходит через LINQ to Objects? Вы вызываете ToList () или ToArray () для своего источника или ссылаетесь на него как IEnumerable перед выполнением этого запроса?


Обновление: После прочтения ваших комментариев я снова проверил это и понял некоторые вещи. Я был неправ, что вы не используете LINQ to SQL. Вы не получили исключение «String.IsNullOrEmpty (String) не поддерживает перевод в SQL» , поскольку IsNullOrEmpty () вызывается для локальной переменной, а не для столбца SQL, поэтому он работает на стороне клиента, даже если вы используете LINQ to SQL (не LINQ to Objects). Так как он работает на стороне клиента, вы можете получить NullReferenceException при вызове этого метода, поскольку он не транслируется в SQL, где вы не можете получить NullReferenceException .

Один из способов сделать ваше решение менее хакерским - это разрешить «null-ness» fromname вне запроса:

string lowerfromname = String.IsNullOrEmpty(fromname) ? fromname : fromname.ToLower();

var messages = from msg in dc.MessageItems
               where String.IsNullOrEmpty(lowerfromname) || msg.Name.ToLower().Contains(lowerfromname)
               select msg.Name;

Обратите внимание, что это не всегда будет переводиться в нечто вроде (используя ваши комментарии в качестве примера):

SELECT ... FROM ... WHERE @theValue IS NULL OR @theValue = theValue

Его перевод будет решен во время выполнения в зависимости от того, является ли из имени нулевым или нет. Если он равен нулю, он будет переведен без предложения WHERE . Если это не ноль, это будет переводиться с простым

4
ответ дан 2 December 2019 в 05:55
поделиться

Вы правы в том, что второе условие не должно оцениваться при использовании компараторов короткого замыкания (см. Какова лучшая практика в отношении оценки короткого замыкания в C #? ), однако я подозреваю, что Linq может попытаться оптимизировать ваш запрос перед его выполнением и при этом изменить порядок выполнения.

Wrapping все это в скобках также, для меня, дает более ясное утверждение, поскольку целое условие «где» содержится в круглых скобках.

0
ответ дан 2 December 2019 в 05:55
поделиться

Как сказал Брайан, я бы посмотрел, если значение msg.FromName равно NULL, прежде чем делать ToLower (). Contains (fromname.ToLower ()))

0
ответ дан 2 December 2019 в 05:55
поделиться

Вы уверены, что это «fromname», что ноль, а не «msg.FromName», это нуль?

3
ответ дан 2 December 2019 в 05:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: