2011-06-23 61 views
83

Tôi đang cố sắp xếp danh sách sản phẩm theo giá của chúng.Thứ tự LINQ theo cột rỗng, trong đó thứ tự tăng dần và giá trị null phải là

Tập kết quả cần liệt kê các sản phẩm theo giá từ thấp đến cao theo cột LowestPrice. Tuy nhiên, cột này là nullable.

tôi có thể sắp xếp danh sách trong thứ tự giảm dần như sau:

var products = from p in _context.Products 
    where p.ProductTypeId == 1 
    orderby p.LowestPrice.HasValue descending 
    orderby p.LowestPrice descending 
    select p; 

// returns: 102, 101, 100, null, null 

Tuy nhiên tôi không thể tìm ra cách sắp xếp này theo thứ tự tăng dần.

// i'd like: 100, 101, 102, null, null 
+3

'orderby p.LowestPrice ?? Int.MaxValue; 'là một cách đơn giản. – PostMan

+2

@PostMan: Vâng, nó đơn giản, nó đạt được kết quả đúng, nhưng 'OrderByDescending, ThenBy' là rõ ràng hơn. – jason

+0

@ Jason, vâng tôi không biết cú pháp cho 'orderby', và có bên theo dõi tìm kiếm nó :) – PostMan

Trả lời

114

Thử đặt cả hai cột vào cùng một thứ tự.

orderby p.LowestPrice.HasValue descending, p.LowestPrice 

Nếu không, mỗi đơn hàng là một hoạt động riêng biệt trên bộ sưu tập sắp xếp lại nó mỗi lần.

Điều này sẽ sắp xếp thứ tự các giá trị có giá trị trước tiên, "sau đó" thứ tự của giá trị.

+3

cổ vũ. rất đơn giản, tôi cảm thấy như một thằng ngốc: P –

+11

Lỗi thường gặp, mọi người làm tương tự với Cú pháp Lamda - sử dụng .OrderBy hai lần thay vì .ThenBy. – DaveShaw

+0

** Công việc này ** để sắp xếp các trường có giá trị ở trên cùng và các trường trống ở dưới cùng tôi đã sử dụng: 'orderby p.LowestPrice == null, p.LowestPrice ascending' Hy vọng sẽ giúp ai đó. – stom

59

Nó thực sự giúp hiểu cú pháp truy vấn LINQ và cách nó được dịch sang các cuộc gọi phương thức LINQ.

Nó chỉ ra rằng

var products = from p in _context.Products 
       where p.ProductTypeId == 1 
       orderby p.LowestPrice.HasValue descending 
       orderby p.LowestPrice descending 
       select p; 

sẽ được dịch bởi trình biên dịch để

var products = _context.Products 
         .Where(p => p.ProductTypeId == 1) 
         .OrderByDescending(p => p.LowestPrice.HasValue) 
         .OrderByDescending(p => p.LowestPrice) 
         .Select(p => p); 

Đây là một cách dứt khoát không phải những gì bạn muốn. Điều này sắp xếp theo thứ tự Product.LowestPrice.HasValue trong descending và sau đó sắp xếp lại toàn bộ bộ sưu tập theo số Product.LowestPrice theo thứ tự descending.

gì bạn muốn là

var products = _context.Products 
         .Where(p => p.ProductTypeId == 1) 
         .OrderByDescending(p => p.LowestPrice.HasValue) 
         .ThenBy(p => p.LowestPrice) 
         .Select(p => p); 

mà bạn có thể có được bằng cách sử dụng cú pháp truy vấn bằng cách

var products = from p in _context.Products 
       where p.ProductTypeId == 1 
       orderby p.LowestPrice.HasValue descending, 
         p.LowestPrice 
       select p; 

Để biết chi tiết của các bản dịch từ cú pháp truy vấn đến các cuộc gọi phương pháp, xem đặc điểm kỹ thuật ngôn ngữ. Nghiêm túc. Đọc nó.

+3

+1 hoặc chỉ ... không viết cú pháp truy vấn LINQ :) Giải thích tốt dù sao – sehe

11

Tôi có tùy chọn khác trong trường hợp này. Danh sách của tôi là objList và tôi phải đặt hàng nhưng không phải là cuối cùng. quyết định của tôi:

var newList = objList.Where(m=>m.Column != null) 
        .OrderBy(m => m.Column) 
        .Concat(objList.where(m=>m.Column == null)); 
+0

Điều này có thể hoạt động trong các tình huống mà bạn muốn có kết quả với các giá trị khác như 0 thay cho null. –

+0

Có. Chỉ cần thay thế null thành 0. –

8

quyết định của tôi:

Array = _context.Products.OrderByDescending(p => p.Val ?? float.MinValue) 
4

Đây là những gì tôi đã đưa ra vì tôi đang sử dụng phương pháp mở rộng và cũng mục của tôi là một chuỗi, do đó không có .HasValue:

.OrderBy(f => f.SomeString == null).ThenBy(f => f.SomeString) 

Tính năng này hoạt động với các đối tượng LINQ 2 trong bộ nhớ. Tôi đã không kiểm tra nó với EF hoặc bất kỳ DB ORM.

4

Tôi đã cố gắng tìm một giải pháp LINQ cho điều này nhưng không thể làm việc nó ra từ câu trả lời ở đây.

câu trả lời cuối cùng của tôi là:

.OrderByDescending(p.LowestPrice.HasValue).ThenBy(p.LowestPrice) 
7

Giải pháp cho các giá trị chuỗi thực sự kỳ lạ:

.OrderBy(f => f.SomeString == null).ThenBy(f => f.SomeString) 

Lý do duy nhất mà làm việc là vì sự biểu hiện đầu tiên, OrderBy(), sắp xếp bool giá trị: true/false. false kết quả đầu tiên theo sau bởi các kết quả true (nullables) và ThenBy() sắp xếp các giá trị không null theo thứ tự bảng chữ cái.

Vì vậy, tôi thích làm điều gì đó dễ đọc hơn như thế này:

.OrderBy(f => f.SomeString ?? "z") 

Nếu SomeString là null, nó sẽ được thay thế bằng "z" và sau đó sắp xếp mọi thứ theo thứ tự abc.

LƯU Ý: Đây không phải là giải pháp cuối cùng vì "z" vượt trước giá trị z như zebra.

CẬP NHẬT 2016/09/06 - Giới thiệu về @jornhd bình luận, nó thực sự là một giải pháp tốt, nhưng nó vẫn còn một chút phức tạp, vì vậy tôi sẽ khuyên bạn nên bọc nó trong một lớp học mở rộng, như thế này:

public static class MyExtensions 
{ 
    public static IOrderedEnumerable<T> NullableOrderBy<T>(this IEnumerable<T> list, Func<T, string> keySelector) 
    { 
     return list.OrderBy(v => keySelector(v) != null ? 0 : 1).ThenBy(keySelector); 
    } 
} 

Và đơn giản sử dụng nó như:

var sortedList = list.NullableOrderBy(f => f.SomeString); 
+1

Tôi nghĩ rằng điều này dễ đọc hơn, không có hằng số khó chịu: .OrderBy (f => f.SomeString! = Null? 0: 1) .ThenBy (f => f.SomeString) – jornhd

Các vấn đề liên quan