2014-09-18 19 views
6

Tôi đã thử một câu lệnh OrderBy đơn giản.LINQ OrderBy. Liệu nó luôn luôn trả về cùng một danh sách theo thứ tự?

Mục tiêu dữ liệu để đặt hàng là một cái gì đó như dưới đây:

[ 
    {"id":40, "description":"aaa", "rate":1}, 
    {"id":1, "description":"bbb", "rate":1}, 
    {"id":4, "description":"ccc", "rate":2}, 
    {"id":19, "description":"aaa", "rate":1} 
] 

Sau đó, tôi đặt mục bằng tài sản tỷ lệ.

Điều kỳ lạ là nếu tôi 'đặt hàng' cho họ, nó 'bỏ qua' một số mục theo một giá trị đã cho và sau đó 'lấy' chỉ phần dữ liệu.

Ví dụ,

var result = items.OrderBy(i => i.rate); 
var result = result.Skip(2); 
var result = result.Take(2); 

Kết quả có vẻ tốt đẹp cho hầu hết của nó, nhưng 'trường hợp cạnh' mục không được trả lại gì cả.

Ví dụ,

nếu kết quả đầu tiên trở lại như

[{"id":40, "description":"aaa", "rate":1}, {"id":1, "description":"bbb", "rate":1}] 

kết quả thứ hai trở lại như

[{"id":1, "description":"bbb", "rate":1}, {"id":4, "description":"ccc", "rate":2}] 

Item "id: 19" đã không được trả lại với cuộc gọi truy vấn thứ hai. Thay vào đó, mục "id: 1" đã trả về hai lần.

Câu hỏi của tôi là câu lệnh OrderBy của SQL không tạo ra cùng một danh sách thứ tự mỗi lần OrderBy đơn đặt hàng bởi một thuộc tính nhất định, nhưng thứ tự chính xác trong nhóm chia sẻ cùng một thuộc tính có thể thay đổi.

Cơ chế chính xác dưới mui xe là gì?

+0

Nếu bạn không chỉ định thứ tự thì không có bảo đảm. Nếu bạn chỉ định một số cột, ví dụ: 'thứ tự theo tỷ lệ, mô tả', sau đó nó sẽ sắp xếp theo' tốc độ' và sau đó, trong đó 'giá trị' giá trị lặp lại,' mô tả'. Vẫn có thể có nhiều hàng có giá trị bằng nhau cho cả 'tốc độ' và' mô tả' và thứ tự của chúng sẽ không được chỉ định. 'id' thường được sử dụng như một bộ ngắt kết nối để đảm bảo thứ tự ổn định:' thứ tự theo tỷ lệ, mô tả, id'. – HABO

+0

Lý do thực tế cho việc tại sao thứ tự có thể khác: Một số thuật toán sắp xếp nhanh sẽ chọn ngẫu nhiên lựa chọn trục. – usr

Trả lời

19

Câu trả lời ngắn: LINQ to Objects sử dụng thuật toán sắp xếp ổn định, và LINQ to SQL phụ thuộc vào việc triển khai cơ sở dữ liệu theo thứ tự thường không xác định.

Thuật toán sắp xếp xác định là thuật toán luôn có cùng hành vi trên các lần chạy khác nhau.

Trong ví dụ này, bạn có các bản sao trong mệnh đề OrderBy của mình. Đối với loại được bảo đảm và được dự đoán, một trong các mệnh đề đơn đặt hàng hoặc kết hợp mệnh đề đơn đặt hàng phải là duy nhất.

Trong LINQ, bạn có thể đạt được điều này bằng cách thêm mệnh đề OrderBy khác để tham chiếu thuộc tính duy nhất của bạn, như trong
items.OrderBy(i => i.Rate).ThenBy(i => i.ID).

Long trả lời:

LINQ to Objects sử dụng một loại ổn định, như tài liệu trong liên kết này: MSDN.

Trong LINQ to SQL, nó phụ thuộc vào thuật toán sắp xếp của cơ sở dữ liệu bên dưới và thường là một kiểu không ổn định, như trong MS SQL Server (MSDN).

Trong một loại ổn định, nếu các phím của hai phần tử bằng nhau, thứ tự của các phần tử được giữ nguyên.Ngược lại, một loại không ổn định không bảo toàn thứ tự các phần tử có cùng khóa.

Wikipedia example

Vì vậy, đối với LINQ to SQL, việc phân loại thường không xác định vì RDMS (Relational Hệ thống quản lý cơ sở dữ liệu, như MS SQL Server) có thể trực tiếp sử dụng một thuật toán sắp xếp ổn định với một lựa chọn trục ngẫu nhiên hoặc sự ngẫu nhiên có thể liên quan đến hàng nào mà cơ sở dữ liệu xảy ra để truy cập đầu tiên trong hệ thống tệp.

Ví dụ: hãy tưởng tượng rằng kích thước của một trang trong hệ thống tệp có thể chứa tối đa 4 hàng.

Trang sẽ được đầy đủ nếu bạn chèn các dữ liệu sau:

 Page 1 
| Name | Value | 
|------|-------| 
| A | 1 | 
| B | 2 | 
| C | 3 | 
| D | 4 | 


Nếu bạn cần phải chèn một hàng mới, các RDMS có hai lựa chọn:

  1. Tạo một trang mới để phân bổ hàng mới.
  2. Chia trang hiện tại thành hai trang. Vì vậy, trang đầu tiên sẽ giữ các Tên AB và trang thứ hai sẽ giữ CD.

Giả sử RDMS chọn tùy chọn 1 (để giảm phân đoạn chỉ mục). Nếu bạn chèn một dòng mới với Tên C và giá trị , bạn sẽ nhận được:

 Page 1    Page 2 
| Name | Value | | Name | Value | 
|------|-------| |------|-------| 
| A | 1 | | C | 9 | 
| B | 2 | |  |  | 
| C | 3 | |  |  | 
| D | 4 | |  |  | 


lẽ, mệnh đề OrderBy trong cột Tên sẽ trở lại như sau:

| Name | Value | 
|------|-------| 
| A | 1 | 
| B | 2 | 
| C | 3 | 
| C | 9 | -- Value 9 appears after because it was at another page 
| D | 4 | 


Bây giờ, giả sử rằng RDMS chọn tùy chọn 2 (để tăng hiệu suất chèn trong hệ thống lưu trữ có nhiều cọc). Nếu bạn chèn một dòng mới với Tên C và giá trị , bạn sẽ nhận được:

 Page 1    Page 2 
| Name | Value | | Name | Value | 
|------|-------| |------|-------| 
| A | 1 | | C | 3 | 
| B | 2 | | D | 4 | 
| C | 9 | |  |  | 
|  |  | |  |  | 


lẽ, mệnh đề OrderBy trong cột Tên sẽ trở lại như sau:

| Name | Value | 
|------|-------| 
| A | 1 | 
| B | 2 | 
| C | 9 | -- Value 9 appears before because it was at the first page 
| C | 3 | 
| D | 4 | 


Về ví dụ của bạn:

Tôi tin rằng bạn đã nhập sai điều gì đó trong câu hỏi của mình, bởi vì bạn đã sử dụng items.OrderBy(i => i.rate).Skip(2).Take(2); và kết quả đầu tiên không hiển thị một hàng với Rate = 2.Điều này là không thể vì Skip sẽ bỏ qua hai hàng đầu tiên và chúng có Rate = 1, vì vậy, đầu ra của bạn phải hiển thị hàng với Rate = 2.

Bạn đã gắn thẻ câu hỏi của mình với database, vì vậy tôi tin rằng bạn đang sử dụng LINQ to SQL. Trong trường hợp này, kết quả có thể không xác định và bạn có thể nhận được như sau:

Kết quả 1:

[{"id":40, "description":"aaa", "rate":1}, 
{"id":4, "description":"ccc", "rate":2}] 

Kết quả 2:

[{"id":1, "description":"bbb", "rate":1}, 
{"id":4, "description":"ccc", "rate":2}] 

Nếu bạn đã sử dụng items.OrderBy(i => i.rate).ThenBy(i => i.ID).Skip(2).Take(2); thì kết quả chỉ có thể sẽ là:

[{"id":40, "description":"aaa", "rate":1}, 
{"id":4, "description":"ccc", "rate":2}] 
+1

Cần lưu ý rằng LINQ cho các đối tượng sử dụng một sắp xếp ổn định cho OrderBy, nhưng một truy vấn LINQ được chuyển đổi sang SQL sẽ sử dụng các nguồn dữ liệu của nó thực hiện ORDER BY. – rdans

+0

Cảm ơn @RyanDansie, tôi đã thêm ghi chú của bạn vào câu trả lời của tôi. – Zanon

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