2012-06-29 29 views
6

Tôi có một truy vấn LINQToEntities mà double tạo ra một truy vấn con khi tạo SQL. Điều này làm cho kết quả được đặt trở lại với kết quả 0-3, mỗi khi truy vấn được chạy. Truy vấn con của riêng nó tạo ra một kết quả ngẫu nhiên duy nhất (như nó cần). Chuyện gì đang xảy ra ở đây?LINqToEntities tạo ra SQL không chính xác (Double Subquery)

Truy vấn LINQ:

from jpj in JobProviderJobs 
where jpj.JobID == 4725 
&& jpj.JobProviderID == (from jp2 in JobProviderJobs 
         where jp2.JobID == 4725 
         orderby Guid.NewGuid() 
         select jp2.JobProviderID).FirstOrDefault() 
select new 
{ 
    JobProviderID = jpj.JobProviderID 
} 

Sản xuất SQL này:

SELECT 
[Filter2].[JobID] AS [JobID], 
[Filter2].[JobProviderID1] AS [JobProviderID] 
FROM (SELECT [Extent1].[JobID] AS [JobID], [Extent1].[JobProviderID] AS [JobProviderID1], [Limit1].[JobProviderID] AS [JobProviderID2] 
    FROM [dbo].[JobProviderJob] AS [Extent1] 
    LEFT OUTER JOIN (SELECT TOP (1) [Project1].[JobProviderID] AS [JobProviderID] 
     FROM (SELECT 
      NEWID() AS [C1], 
      [Extent2].[JobProviderID] AS [JobProviderID] 
      FROM [dbo].[JobProviderJob] AS [Extent2] 
      WHERE 4725 = [Extent2].[JobID] 
     ) AS [Project1] 
     ORDER BY [Project1].[C1] ASC) AS [Limit1] ON 1 = 1 
    WHERE 4725 = [Extent1].[JobID]) AS [Filter2] 
LEFT OUTER JOIN (SELECT TOP (1) [Project2].[JobProviderID] AS [JobProviderID] 
    FROM (SELECT 
     NEWID() AS [C1], 
     [Extent3].[JobProviderID] AS [JobProviderID] 
     FROM [dbo].[JobProviderJob] AS [Extent3] 
     WHERE 4725 = [Extent3].[JobID] 
    ) AS [Project2] 
    ORDER BY [Project2].[C1] ASC) AS [Limit2] ON 1 = 1 
WHERE [Filter2].[JobProviderID1] = (CASE WHEN ([Filter2].[JobProviderID2] IS NULL) THEN 0 ELSE [Limit2].[JobProviderID] END) 

EDIT:

Vì vậy, việc thay đổi subquery để các công trình này, nhưng tôi không có ý tưởng tại sao

(from jp2 in JobProviderJobs 
    where jp2.JobID == 4725 
    orderby Guid.NewGuid() 
    select jp2).FirstOrDefault().JobProviderID 

Trả lời

3

Điều này xảy ra do hành vi mong đợi của FirstOrDefault(). Gọi FirstOrDefault() trên một bộ sản phẩm nào của JobProviderJobs sẽ tạo ra giá trị null, nhưng gọi nó trên một bộ trống int s sẽ tạo ra một 0. Nhận ra điều này, LINQ to Entities cố gắng gọi một câu lệnh case ở cuối truy vấn để đảm bảo rằng nếu không có JobProviderJobs nào phù hợp, kết quả của lựa chọn sẽ là 0 thay vì null.

Trong hầu hết các trường hợp, việc tạo lại phép chiếu bên trong sẽ không gây ra vấn đề gì, nhưng việc sử dụng NewGuid() của bạn rõ ràng sẽ loại bỏ logic này.

Bạn đã tìm thấy một giải pháp. Một yếu tố khác là để đúc kết quả của biểu thức bên trong như vậy:

from jpj in JobProviderJobs 
where jpj.JobID == 4725 
&& jpj.JobProviderID == (from jp2 in JobProviderJobs 
         where jp2.JobID == 4725 
         orderby Guid.NewGuid() 
         select (int?) jp2.JobProviderID).FirstOrDefault() 
select new 
{ 
    JobProviderID = jpj.JobProviderID 
} 

Việc triển khai SQL chính xác hơn sẽ sử dụng lại dự đoán tương đương. Có khả năng trình phân tích cú pháp đơn giản không đủ phức tạp để xử lý đúng cách này và các nhà phát triển không bao giờ thấy cần sửa lỗi vì SQL Server sẽ có thể tối ưu hóa các dự đoán giống hệt nhau miễn là chúng xác định.

Có thể bạn nên đăng nhập một báo cáo lỗi về điều này nếu một báo cáo chưa tồn tại.

+1

Ước gì tôi có thể cộng 3. Câu trả lời hoàn hảo: Giải thích về hành vi, giải pháp và sử dụng từ "do đó" =) – Tyrsius

+0

@Tyrsius: Tôi đã có [thành công] (http://connect.microsoft.com/VisualStudio/feedback/details/658392/linq-to-entity-orderby-là-mất-khi-theo-by-firstordefault) lỗi đăng nhập dưới [Visual Studio và .NET] (https://connect.microsoft.com/VisualStudio/ Phản hồi) – StriplingWarrior

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