2010-08-24 37 views
7

Tôi đang gặp khó khăn khi nhận cú pháp LINQ .. Làm cách nào để thực hiện lệnh này một cách tốt hơn?Thực hiện truy vấn LINQ tốt hơn

var user = (from u in context.users 
      where u.email.Equals(email) 
      select u).Single(); 
var pinToUser = (from ptu in context.pintousers 
       where ptu.user_id.Equals(user.id) 
       select ptu).Single(); 
var pin = (from p in context.pins 
      where p.idpin.Equals(pinToUser.pin_idpin) 
      select p).Single(); 

return pin; 

Như bạn có thể thấy, có một người dùng bảng, bàn pintouser và ghim bàn. Pintouser tham khảo người dùng và pin. Có thể viết một cái gì đó ngắn như "user.pintouser.pin"? Tôi nghĩ rằng tôi có các thuộc tính điều hướng tất cả được thiết lập nhưng tôi không chắc chắn làm thế nào để sử dụng chúng đúng cách hoặc nếu tôi có thể làm cho chúng tốt hơn bằng cách sửa đổi chúng.

Cảm ơn bạn đã đọc

+0

Bạn có thể viết lại điều này dưới dạng một truy vấn đơn lẻ. – leppie

Trả lời

8

Sử dụng kết nối để viết lại mọi thứ dưới dạng một truy vấn đơn giản. Nếu tôi đọc câu hỏi của bạn đúng cách, điều này sẽ cung cấp cho bạn kết quả chính xác:

var pin = (from u in context.users 
      join ptu in context.pintousers on u.id equals ptu.user_id 
      join p in context.pins on ptu.pin_idpin equals p.idpin 
      where u.email == email 
      select p).Single(); 

Hãy ghi nhớ, tuy nhiên, rằng nếu truy vấn này trả về bất cứ điều gì khác hơn là một kết quả duy nhất mã của bạn sẽ ném một ngoại lệ.

Nếu bạn muốn xử lý khả năng nhận một hoặc không có hàng thì bạn nên sử dụng SingleOrDefault().

Nếu bạn muốn xử lý khả năng nhận được bất kỳ số hàng nào thì bạn thực sự nên sử dụng FirstOrDefault().

+0

Chà, thật nhanh. Cảm ơn bạn, nó hoạt động và điều này đã cho tôi một số cái nhìn sâu sắc trong việc sử dụng tham gia! – Phil

+0

Truy vấn gốc trả về một mã pin duy nhất. Của bạn trả về một IQueryable hoặc một số như vậy. – recursive

+0

@recursive - Bạn nói đúng, tôi đã tập trung vào việc tham gia và quên cuộc gọi tới Single(). Đã sửa. –

2

Bạn nên sử dụng join, như @JustinNiessner chỉ ra, nhưng đây là một cách khác để viết truy vấn của bạn.

var user = context.users.Single(u => u.email == email); 
var pinToUser = context.pintousers.Single(ptu => ptu.user_id == user.id); 
var pin = context.pins.Single(p => p.idpin == pinToUser.pin_idpid); 
1

Vì bạn có đặc tính chuyển hướng, cũng có thể sử dụng chúng:

Pin pin = 
(
    from u in context.Users 
    where u.email == email 
    from ptu in u.pintousers 
    let p = ptu.pin 
    select p 
).Single(); 
+0

lệnh "let" làm gì? – Phil

+0

như bạn có thể khai báo một biến bên trong một vòng lặp, tạo ra một biến cho mỗi vòng lặp lặp ... "cho phép" cho phép bạn khai báo một biến cho mỗi hàng trong truy vấn. –

3

Lưu ý rằng nếu bạn có mối quan hệ ngoại-key của bạn thiết righ trong cơ sở dữ liệu của bạn, LINQ-to-SQL nên có tham gia cho bạn tự động:

var pin = (from u in context.users 
     where u.email == email 
     select u.pintouser.pin).Single(); 

có nghĩa là bạn có thể giảm xuống còn:

var pin = context.users.Where(u=>u.email == email) 
         .Select(u=>u.pintouser.pin) 
         .Single(); 

(Cập nhật: Lưu ý: Ban đầu tôi đã gợi ý những điều sau đây, đó là ngắn hơn nhiều, nhưng tôi tin rằng nó sẽ gây ra hai vòng quanh chuyến đi đến cơ sở dữ liệu)

var pin = context.users.Single(u=>u.email == email).Single().pintouser.pin; 

Bây giờ, .pintouser.pin là an toàn, bởi vì Single() sẽ luôn trả về đối tượng user (hoặc ném ngoại lệ).

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