2012-03-12 63 views
10

Tôi gặp sự cố khi xây dựng một truy vấn LINQ khá tốn kém. Về cơ bản tôi có một tình huống mà theo đó tôi cần phải thực hiện một truy vấn phụ trong một vòng lặp để lọc xuống số lượng các trận đấu được trả về từ cơ sở dữ liệu. mã ví dụ là trong vòng lặp này dưới đây:LINQ nhiều nơi truy vấn

 foreach (Guid parent in parentAttributes) 
     { 
      var subQuery = from sc in db.tSearchIndexes 
          join a in db.tAttributes on sc.AttributeGUID equals a.GUID 
          join pc in db.tPeopleIndexes on a.GUID equals pc.AttributeGUID 
          where a.RelatedGUID == parent && userId == pc.CPSGUID        
          select sc.CPSGUID; 

      query = query.Where(x => subQuery.Contains(x.Id)); 
     } 

Khi tôi sau đó gọi ToList() trên các biến truy vấn có vẻ như chỉ có một một trong những truy vấn con đã được thực hiện và tôi là trái với một xô dữ liệu Tôi không yêu cầu. Tuy nhiên phương pháp này hoạt động:

 IList<Guid> temp = query.Select(x => x.Id).ToList(); 

     foreach (Guid parent in parentAttributes) 
     { 
      var subQuery = from sc in db.tSearchIndexes 
          join a in db.tAttributes on sc.AttributeGUID equals a.GUID 
          join pc in db.tPeopleIndexes on a.GUID equals pc.AttributeGUID 
          where a.RelatedGUID == parent && userId == pc.CPSGUID        
          select sc.CPSGUID; 

      temp = temp.Intersect(subQuery).ToList(); 
     } 

     query = query.Where(x => temp.Contains(x.Id)); 

Đáng tiếc là phương pháp này là khó chịu vì nó dẫn đến nhiều truy vấn đến các cơ sở dữ liệu từ xa, theo đó các phương pháp tiếp cận ban đầu nếu tôi có thể có được nó làm việc sẽ chỉ dẫn đến một hit duy nhất. Bất kỳ ý tưởng?

Trả lời

8

Tôi nghĩ bạn đang đánh một trường hợp đặc biệt để nắm bắt biến vòng lặp trong biểu thức lambda được sử dụng để lọc. Còn được gọi là truy cập vào lỗi đóng bị sửa đổi.

Hãy thử điều này:

foreach (Guid parentLoop in parentAttributes) 
    { 
     var parent = parentLoop; 
     var subQuery = from sc in db.tSearchIndexes 
         join a in db.tAttributes on sc.AttributeGUID equals a.GUID 
         join pc in db.tPeopleIndexes on a.GUID equals pc.AttributeGUID 
         where a.RelatedGUID == parent && userId == pc.CPSGUID        
         select sc.CPSGUID; 

     query = query.Where(x => subQuery.Contains(x.Id)); 
    } 

Vấn đề là nắm bắt được parent biến trong việc đóng cửa (mà cú pháp LINQ được chuyển đổi sang), gây ra tất cả các subQuery es được chạy với id cùng cha mẹ.

Điều gì xảy ra là trình biên dịch tạo ra một lớp để giữ đại biểu và các biến cục bộ mà người được ủy quyền truy cập. Trình biên dịch tái sử dụng cùng một thể hiện của lớp đó cho mỗi vòng lặp; và do đó, khi truy vấn được thực hiện, tất cả các số Where thực hiện cùng một hướng dẫn parent, là lệnh cuối cùng thực hiện.

Khai báo parent bên trong phạm vi vòng lặp làm cho trình biên dịch về cơ bản tạo bản sao của biến, với giá trị chính xác, được ghi lại.

Điều này có thể hơi khó nắm bắt lúc đầu, vì vậy nếu đây là lần đầu tiên nó đánh bạn; Tôi khuyên bạn nên hai bài báo này cho nền và một lời giải thích thấu đáo:

+0

+1 Nếu bạn muốn hiểu khái niệm này nhiều hơn, hãy xem câu trả lời của Skeet tại đây và bài viết được tham chiếu của anh ấy. http://stackoverflow.com/questions/271440/c-sharp-captured-variable-in-loop –

+0

@DMoses cảm ơn, tôi đã thêm một số liên kết, thừa nhận đầy đủ rằng tôi không thể giải thích điều này là thanh lịch và chính xác như các quý ông Lippert và Skeet :-) – driis

+0

Cảm ơn bạn driis. Làm việc như người ở. Bạn là một vị thánh và một học giả. – kh25

0

Có lẽ theo cách này?

var subQuery = from sc in db.tSearchIndexes 
       join a in db.tAttributes on sc.AttributeGUID equals a.GUID 
       join pc in db.tPeopleIndexes on a.GUID equals pc.AttributeGUID 
       where parentAttributes.Contains(a.RelatedGUID) && userId == pc.CPSGUID        
       select sc.CPSGUID; 
+0

Cảm ơn bạn đã phản ứng k06a nhưng truy vấn ở trên đang cố gắng (nhưng không thành công) trong việc làm điều gì đó hơi khác so với truy vấn bạn đã trình bày. Về cơ bản tôi đang lọc bởi tất cả các parentAttributes trong khi bạn đang lọc bởi bất kỳ vì vậy điều này sẽ trả về một tập hợp lớn hơn các kết quả. – kh25

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