Mã Linq để chọn một mặt hàng


105

Tôi thấy mình viết rất nhiều mã như thế này để chọn một mục phù hợp

var item = (from x in Items where x.Id == 123 select x).First();

Có cách nào tốt hơn để làm điều đó không hoặc cách này ngắn gọn như tôi sắp làm?

CHỈNH SỬA: Nên đã nói "Cách sử dụng cú pháp linq sạch hơn". Tôi đã biết về cú pháp lambda và nó bắt đầu giống như đây thực sự là cách duy nhất. Tôi đã nhận được một số thông tin hữu ích, vì vậy cảm ơn tất cả những người đã trả lời.


5
Cá nhân tôi tránh Single()SingleOrDefault()NẾU tôi biết dữ liệu đã là duy nhất (ví dụ: từ cơ sở dữ liệu có ràng buộc đó, v.v.), vì Single()buộc nó phải quét phần còn lại của danh sách để tìm bản sao có thể xảy ra, nhưng đó là tôi. Nếu bạn cần thực thi tính duy nhất của mình tại thời điểm này, hãy sử dụng Single()gia đình, nếu không, hãy sử dụng First()gia đình.
James Michael Hare

Câu trả lời:


176

Tùy thuộc vào mức độ bạn thích cú pháp truy vấn linq, bạn có thể sử dụng các phương thức mở rộng trực tiếp như:

var item = Items.First(i => i.Id == 123);

Và nếu bạn không muốn gặp lỗi nếu danh sách trống, hãy sử dụng FirstOrDefaultgiá trị này trả về giá trị mặc định cho loại phần tử ( nullđối với các loại tham chiếu):

var item = Items.FirstOrDefault(i => i.Id == 123);

if (item != null)
{
    // found it
}

Single()SingleOrDefault()cũng có thể được sử dụng, nhưng nếu bạn đang đọc từ cơ sở dữ liệu hoặc thứ gì đó đã đảm bảo tính duy nhất, tôi sẽ không bận tâm vì nó phải quét danh sách để xem có bất kỳ bản sao và ném nào không. First()FirstOrDefault()dừng ở trận đấu đầu tiên, để chúng hoạt động hiệu quả hơn.

Về gia đình First()Single()gia đình, đây là nơi họ ném:

  • First() - ném nếu trống / không tìm thấy, không ném nếu trùng lặp
  • FirstOrDefault() - trả về mặc định nếu trống / không tìm thấy, không ném nếu trùng lặp
  • Single() - ném nếu trống / không tìm thấy, ném nếu tồn tại bản sao
  • SingleOrDefault() - trả về mặc định nếu trống / không tìm thấy, ném nếu bản sao tồn tại

1
Tôi nghĩ rằng bạn đang thiếu hai dấu bằng ở đó. Nêni.Id == 123
davehale23

18

FirstOrDefault hoặc SingleOrDefault có thể hữu ích, tùy thuộc vào trường hợp của bạn và liệu bạn có muốn xử lý việc không có hoặc nhiều hơn một kết quả phù hợp hay không:

FirstOrDefault: Trả về phần tử đầu tiên của một chuỗi hoặc một giá trị mặc định nếu không tìm thấy phần tử nào.

SingleOrDefault: Trả về phần tử duy nhất của một chuỗi hoặc một giá trị mặc định nếu chuỗi trống; phương thức này ném một ngoại lệ nếu có nhiều hơn một phần tử trong chuỗi

Tôi không biết điều này hoạt động như thế nào trong truy vấn linq 'from' nhưng trong cú pháp lambda, nó trông như thế này:

var item1 = Items.FirstOrDefault(x => x.Id == 123);
var item2 = Items.SingleOrDefault(x => x.Id == 123);

cái nào là hiệu quả nhất về thời gian DB? Nếu tôi có một varchar, tôi muốn có một kết hợp chính xác nhưng có thể không có?
Piotr Kula

2
Câu trả lời được chấp nhận giải quyết đầy đủ vấn đề này, nhưng về cơ bản FirstOrDefault dừng ngay khi tìm thấy một kết quả phù hợp, nhưng SingleOrDefault phải kiểm tra toàn bộ danh sách để đảm bảo có chính xác một kết quả phù hợp.
stuartd

12

Đây là những phương pháp ưa thích:

var item = Items.SingleOrDefault(x => x.Id == 123);

Hoặc là

var item = Items.Single(x => x.Id == 123);

Cảm ơn - vì vậy trong tình huống này không có ký hiệu linq và tôi cần sử dụng lambdas?
Mikey Hogarth

Đó là khá tốt. Tôi chưa thực sự sử dụng linq nhiều, vì vậy tôi không chắc mình thậm chí còn biết về các phương pháp này.
Luongoghe

1
Phương thức đơn kiểm tra xem giá trị trả về là duy nhất. Vì vậy, nếu bộ sưu tập của bạn lớn, nó có thể mất rất nhiều thời gian. Phương thức đầu tiên chỉ trả về phần tử đầu tiên phù hợp với vị từ.
meziantou

@wageoghe James 'answer không sử dụng linq - các phương thức Single và SingleOrDefault là một phần của việc triển khai IEnumerable.
Mikey Hogarth

12

Chỉ để làm cho cuộc sống của ai đó dễ dàng hơn, truy vấn linq với biểu thức lambda

(from x in Items where x.Id == 123 select x).FirstOrDefault();

dẫn đến một truy vấn SQL với một select top (1)trong đó.


9

Điều đó tốt hơn có thể được cô đọng lại ở đây.

var item = Items.First(x => x.Id == 123);

Truy vấn của bạn hiện đang thu thập tất cả các kết quả (và có thể có nhiều hơn một) trong danh sách và sau đó lấy kết quả đầu tiên từ tập hợp đó , thực hiện nhiều công việc hơn mức cần thiết.

Single / SingleOrDefault rất đáng giá, nhưng chỉ khi bạn muốn lặp lại toàn bộ bộ sưu tập và xác minh rằng kết hợp là duy nhất ngoài việc chọn kết hợp đó. First / FirstOrDefault sẽ chỉ thực hiện trận đấu đầu tiên và rời đi, bất kể có bao nhiêu bản sao thực sự tồn tại.


4

Bạn có thể sử dụng cú pháp phương thức tiện ích mở rộng:

var item = Items.Select(x => x.Id == 123).FirstOrDefault();

Ngoài ra, tôi không chắc bạn có thể hiểu ngắn gọn hơn bao nhiêu, nếu không có thể viết các phương thức mở rộng "First" và "FirstOrDefault" chuyên biệt của riêng bạn.


Tôi không nghĩ đây là hành vi có chủ đích. Lệnh Chọn này trả về (thực ra không, nhưng nó chọn để trả về) một tập hợp bool, một bool cho mỗi phần tử của Item, phần tử đầu tiên được trả về dưới dạng item, đơn giản trở thành bool. Sử dụng giải pháp của Chris Hannon
Leonardo Daga

Có lẽ ý bạn là Wheretrái ngược với Select, điều đã được nêu, nhưng câu trả lời này không chính xác. Chọn trong c # làm thay đổi kết quả để IEnumerable <bool>, vì vậy bạn đang nhận được boolcho mục đầu tiênx.Id == 123
bradlis7

2

Tôi sẽ cho bạn biết điều gì đã làm việc cho tôi:

int id = int.Parse(insertItem.OwnerTableView.DataKeyValues[insertItem.ItemIndex]["id_usuario"].ToString());

var query = user.First(x => x.id_usuario == id);
tbUsername.Text = query.username;
tbEmail.Text = query.email;
tbPassword.Text = query.password;

Id của tôi là hàng tôi muốn truy vấn, trong trường hợp này tôi lấy nó từ radGrid, sau đó tôi sử dụng nó để truy vấn, nhưng truy vấn này trả về một hàng, sau đó bạn có thể gán các giá trị bạn nhận được từ truy vấn vào hộp văn bản hoặc bất kỳ thứ gì , Tôi đã phải gán chúng vào hộp văn bản.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.