2009-09-14 56 views
8

Tôi có phương pháp mở rộng C# trên IQueryable, ví dụ: FindNewCustomers()FindCustomersRegisteredAfter(int year) và vv mà tôi sử dụng để "chuỗi" một truy vấn với nhau cho LINQ to SQL.Vấn đề truy vấn được biên dịch từ LINQ to SQL (hoạt động như truy vấn chưa được biên dịch)

Bây giờ đến vấn đề của tôi: Tôi muốn tạo ra các truy vấn biên soạn, ví dụ .:

private static Func<MyDataContext, SearchInfo, IQueryable<Customer>> 
     CQFindAll = 
      CompiledQuery.Compile((MyDataContext dc, SearchInfo info) => 
       dc.Contacts.Select(c => c).FindCustomersRegisteredAfter(info.RegYear) 
          .OrderBy(info.OrderInfo) 
          .Skip(info.SkipCount) 
          .Take(info.PageSize)); 

Phương pháp FindCustomersRegisteredAfter(int year) là một phương pháp khuyến nông tham gia một IQueryable và trở về như cũ. Phương thức OrderBy cũng là một phương thức mở rộng (System.Linq.Dynamic), tạo ra một biểu thức động dựa trên một chuỗi (ví dụ: "FirstName ASC" sẽ sắp xếp trường FirstName tăng dần). SkipTake là các phương pháp tích hợp sẵn.

Truy vấn trên (không phải là được biên dịch, nhưng truy vấn thông thường) hoạt động hoàn hảo. Khi tôi đặt nó trong một truy vấn biên soạn, tôi nhấn các lỗi sau:

Method 'System.Linq.IQueryable`1[Domain.Customer] FindCustomersRegisteredAfter[Customer](System.Linq.IQueryable`1[Domain.Customer], Int32)' has no supported translation to SQL.

Một lần nữa, này hoạt động hoàn hảo nếu truy vấn là không biên soạn, chỉ cần một truy vấn LINQ thường xuyên. Lỗi này chỉ xuất hiện khi nó nằm bên trong CompiledQuery.Compile().

Help ??!

Edit: Nếu tôi tạo ra các truy vấn qua var query = (...) theo cùng một cách như bên trong CompiledQuery.Compile, đây là SQL tạo:

SELECT [t1].[Id], [t1].[FirstName], [t1].[LastName], 
     [t1].[RegYear], [t1].[DeletedOn] 
FROM (
SELECT ROW_NUMBER() OVER (ORDER BY [t0].[LastName]) AS [ROW_NUMBER], 
     [t0].[Id], [t0].[FirstName], [t0].[LastName], [t0].[RegYear], 
     [t0].[DeletedOn] 
FROM [dbo].[Contacts] AS [t0] 
WHERE ([t0].[RegYear] > @p0) AND ([t0].[DeletedOn] IS NULL) 
    ) AS [t1] 
WHERE [t1].[ROW_NUMBER] BETWEEN @p1 + 1 AND @p1 + @p2 
ORDER BY [t1].[ROW_NUMBER] 

Vì vậy, bạn thấy rằng SQL hoàn toàn có thể dịch được nên tôi chỉ cần điền vào @ p0, @ p1 và @ p2 để làm việc này lặp đi lặp lại! Có gì sai với CompiledQuery.Compile?!?

Cập nhật: Tôi hiểu rằng OrderBy không thể hoạt động (vì đây không phải là tham số @p). Tôi vẫn đang cố gắng tìm ra lý do tại sao CompiledQuery.Compile sẽ không hoạt động với các phương thức mở rộng của tôi. Thông tin trên internet cho chủ đề này hầu như không tồn tại.

+5

Tôi không hiểu tại sao đây là wiki cộng đồng. – JustLoren

Trả lời

3

Tôi tin rằng truy vấn được biên dịch phải có thể dịch sang SQL, mà phương thức mở rộng của bạn không thể. Nếu bạn cấu hình SQL được tạo bởi truy vấn "thông thường", bạn có thể thấy rằng nó đang chọn toàn bộ bảng để có thể nạp tất cả các hàng vào phương thức mở rộng của bạn.

Bạn nên làm tốt hơn để đặt logic lọc của mình trong truy vấn (như một phần của cây biểu thức) để nó có thể được dịch sang SQL và chạy phía máy chủ.

OrderBy cũng là một vấn đề vì Bỏ qua. Bạn cần phải làm cho điều này có thể dịch sang SQL hoặc LINQ sẽ phải trả về tất cả các hàng để lọc chúng xuống phía máy khách.

Nếu bạn không thể diễn tả chúng dưới dạng biểu thức LINQ, hãy xem xét việc tạo các hàm SQL trên máy chủ và ánh xạ chúng vào DataContext của bạn. LINQ sẽ có thể dịch chúng thành các cuộc gọi hàm T-SQL.

CHỈNH SỬA:

Tôi đoán tôi đã giả định phương pháp tiện ích của bạn không xây dựng cây biểu thức. Lấy làm tiếc.

Hãy xem xét điều này link có vẻ tương tự với sự cố của bạn.Nó tham khảo một số link khác.

Dường như MethodCallExpression là vấn đề.

The code is a bit long to be posted here, but similar to tomasp.net's expander, I visit every expression in the expression tree and if the node is a MethodCallExpression which calls a method that returns an expression tree, I replace that MethodCallExpression by the expression tree returned by invoking the method.

Vì vậy, nó xuất hiện vấn đề là khi biên dịch truy vấn, phương pháp này không được thực hiện vì vậy không có cây biểu thức để dịch để SQL.

+0

Khi tôi tạo ra một điểm break tôi có thể thấy rằng SQL có thể dễ dàng được tạo ra hoàn toàn (bao gồm bỏ qua, lấy, orderby vv) miễn là nó không phải là một truy vấn được biên dịch. – Alex

+0

Tôi đã chỉnh sửa bài đăng để hiển thị SQL được tạo. – Alex

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