2011-08-06 4 views
95

У меня есть этот запрос:Макс возвращается значение, если пустой запрос

int maxShoeSize=Workers.Where(x=>x.CompanyId==8).Max(x=>x.ShoeSize); 

Что будет в maxShoeSize, если компания 8 не имеет рабочих вообще?

UPDATE:
Как я могу изменить запрос, чтобы получить 0, а не исключение?

+0

Naor : Вы слышали о LINQPad? –

+2

Любой, кто проголосует, опишите почему. – Naor

+5

не мой нисходящий, но, по-видимому, потому, что вы могли легко убедиться в себе. –

ответ

165
int maxShoeSize = Workers.Where(x => x.CompanyId == 8) 
         .Select(x => x.ShoeSize) 
         .DefaultIfEmpty(0) 
         .Max(); 

Нуль в DefaultIfEmpty не является необходимым.

3

Макс выбросит System.InvalidOperationException "Последовательность не содержит элементов"

class Program 
{ 
    static void Main(string[] args) 
    { 
     List<MyClass> list = new List<MyClass>(); 

     list.Add(new MyClass() { Value = 2 }); 

     IEnumerable<MyClass> iterator = list.Where(x => x.Value == 3); // empty iterator. 

     int max = iterator.Max(x => x.Value); // throws System.InvalidOperationException 
    } 
} 

class MyClass 
{ 
    public int Value; 
} 
1
int maxShoeSize=Workers.Where(x=>x.CompanyId==8) 
    .Max(x=>(int?)x.ShoeSize).GetValueOrDefault(); 

(при условии, что ShoeSize имеет тип int)

If Workers является DbSet или ObjectSet от Entity Framework ваш первоначальный запрос будет генерировать InvalidOperationException, но не жалуется на пустую последовательность, но жалуется, что материализованное значение NULL не может быть преобразовано int o a int.

15
int maxShoeSize = Workers.Where(x => x.CompanyId == 8) 
        .Select(x => x.ShoeSize) 
        .DefaultIfEmpty() 
        .Max(); 
1

NB: запрос с DefaultIfEmpty() может быть значительно более медленным. В моем случае это был простой запрос с .DefaultIfEmpty(DateTime.Now.Date).

Я слишком ленив, чтобы профиль. Но, очевидно, EF попытался получить все строки, а затем взять значение Max().

Заключение: иногда обработка InvalidOperationException может быть лучшим выбором.

28

Я знаю, что это старый вопрос, и принятый ответ работает, но этот вопрос ответил на мой вопрос о том, приведет ли такой пустой набор к исключению или к результату default(int).

Однако принятый ответ, хотя он и работает, не является идеальным решением IMHO, которое здесь не приводится. Таким образом, я предоставляю его в своем собственном ответе на благо любого, кто его ищет. Исходный код

Ор был:

int maxShoeSize = Workers.Where(x => x.CompanyId == 8).Max(x => x.ShoeSize); 

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

int maxShoeSize = Workers.Where(x => x.CompanyId == 8).Max(x => x.ShoeSize as int?) ?? 0; 

Это приводит к тому, тип возвращаемого значения функции Max в int?, что позволяет получить результат null, а затем ?? заменяет результат null на 0.

+1

Отличное решение! Более популярный ответ 'DefaultIfEmpty' работает только тогда, когда' Max' не делает оценку. – McGuireV10

+0

@ McGuireV10 Да, мне обычно не нравится использовать 'Select' в качестве среднего человека, когда я просто собираюсь использовать в качестве результата совокупную функцию типа Max. Я также _think_ (я еще не тестировал это), что сгенерированный SQL будет использовать дополнительный запрос подзапроса, выполнив это, в то время как мой будет иметь дело с пустым набором, возвращая null. Спасибо за поддержку и отзывы! ;) – CptRobby

+0

@ McGuireV10 Аналогично, если 'ShoeSize' фактически был связан с сущностью' Uniform', я бы не использовал 'Workers.Where (x => x.CompanyId == 8). Выберите (x => x.Uniform) .Max (x => x.ShoeSize) ', вместо этого я бы просто сохранил всю оценку в функции' Max': 'Workers.Where (x => x.CompanyId == 8) .Max (x => x.Uniform.ShoeSize)'. Я предпочитаю использовать как можно меньше методов в своих запросах, чтобы позволить EF иметь наибольшую свободу при принятии решения о том, как эффективно создавать запросы. ;-) – CptRobby

0

Вы можете использовать тернар в пределах .Max() для обработки предиката и установить его значение;

// assumes Workers != null && Workers.Count() > 0 
int maxShoeSize = Workers.Max(x => (x.CompanyId == 8) ? x.ShoeSize : 0); 

Вам необходимо будет обрабатывать Workers коллекция является пустой/пустой, если это возможно, но это будет зависеть от реализации.

0

Вы можете попробовать это:

int maxShoeSize = Workers.Where(x=>x.CompanyId == 8).Max(x => x.ShoeSize) ?? 0; 
0

Вы можете проверить, есть ли какие-либо рабочие, прежде чем делать Макс().

private int FindMaxShoeSize(IList<MyClass> workers) { 
    var workersInCompany = workers.Where(x => x.CompanyId == 8); 
    if(!workersInCompany.Any()) { return 0; } 
    return workersInCompany.Max(x => x.ShoeSize); 
} 
0

Если это Linq к SQL, я не хотел бы использовать любой(), так как это приводит к несколько запросов к серверу SQL.

Если ShoeSize не обнуляемым поле, а затем, используя только .Max(..) ?? 0 не будет работать, но следующий будет:

int maxShoeSize = Workers.Where(x = >x.CompanyId == 8).Max(x => (int?)x.ShoeSize) ?? 0; 

Это абсолютно не меняет излучаемого SQL, но она возвращает 0, если последовательность пуст, потому что он меняет Max(), чтобы вернуть int? вместо int.

Смежные вопросы