2013-08-26 24 views
12

Tôi có một số mã đã được nâng cấp gần đây từ EF 4.2 lên EF 5.0 (thực ra là EF 4.4 kể từ khi tôi chạy trên .Net 4.0). Tôi đã phát hiện ra rằng tôi phải thay đổi cú pháp truy vấn của mình và tôi tò mò là tại sao. Hãy để tôi bắt đầu với vấn đề.Tại sao EF 5.0 không hỗ trợ cú pháp EF 4.x LINQ này khi biên dịch thành sql?

Tôi có bảng EventLog được điền bởi máy khách theo định kỳ. Đối với mỗi bản ghi sự kiện, một mục được tạo trong bảng Báo cáo. Đây là truy vấn chạy theo định kỳ để khám phá bất kỳ nhật ký sự kiện nào chưa có mục nhập trong bảng Báo cáo. Các truy vấn tôi được sử dụng trong EF 4.2 là:

from el in _repository.EventLogs 
where !_repository.Reports.Any(p => p.EventLogID == el.EventlogID) 

Kể từ khi nâng cấp lên EF 5.0 tôi nhận được lỗi sau khi chạy:

System.NotSupportedException: Không thể để tạo ra một giá trị không đổi của gõ 'Namespace .Bài báo cáo'. Chỉ các loại nguyên thủy hoặc kiểu liệt kê mới được hỗ trợ trong ngữ cảnh này.

Tôi phát hiện ra rằng viết lại nó với cú pháp tham gia đã khắc phục sự cố. Các công trình sau đây trong EF 5.0 và là xấp xỉ tương đương:

from eventLog in _repository.EventLogs 
join report in _repository.Reports on eventLog.EventlogID equals report.EventLogID into alreadyReported 
where !alreadyReported.Any() 

Một số người có thể có ý kiến ​​trái chiều về cú pháp hỗn hợp/phong cách của truy vấn đầu tiên, nhưng tôi thực sự quan tâm nhiều hơn trong các lý do tại sao điều này. Có vẻ kỳ lạ khi trình biên dịch EF 4.2 có thể tạo ra câu lệnh SQL cho truy vấn ban đầu nhưng EF 5.0 từ chối. Đây có phải là một thiết lập mà tôi đang thiếu hoặc chỉ là một sự thắt chặt các ràng buộc giữa hai? Tại sao chuyện này đang xảy ra?

+0

Cá nhân tôi nghĩ rằng nó dễ đọc hơn nhiều như một truy vấn với sự tham gia .. –

+1

Bạn có thể kiểm tra điều này thay vì 'từ el trong _repository.EventLogs nơi _repository.Reports.All (p => p.EventLogID! = El.EventlogID) '? –

+0

Hey King, tôi đã thử điều đó và nhận được điều tương tự. Tôi thậm chí đã cố gắng:! _repository.OntarioReports.Any (p => 5 == 5). Nó có vẻ là cú pháp hỗn hợp từ những gì tôi có thể nói. –

Trả lời

2

Vấn đề là do kiểu trả về bởi kho của bạn; vấn đề có thể được sao chép khi _repository.Reports không phải là IQueryable<T>. Trong trường hợp đó, Reports được coi là biến không vô hướng; mà không được phép trong LINQ. Xem Referencing Non-Scalar Variables Not Supported

Về câu hỏi của bạn về lý do truy vấn thứ hai hoạt động, về cơ bản, phương pháp mở rộng sau là IQueryable<T> nhóm nào tham gia với IEnumerable<TInner>.

public static IQueryable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>(
    this IQueryable<TOuter> outer,IEnumerable<TInner> inner, 
    Expression<Func<TOuter, TKey>> outerKeySelector, 
    Expression<Func<TInner, TKey>> innerKeySelector, 
    Expression<Func<TOuter, IEnumerable<TInner>, TResult>> resultSelector) 

Chỉ chấp nhận biểu thức cho bộ chọn khóa cho cả bên ngoài và bên trong (thay vì tham chiếu biến vô hướng); trong đó ràng buộc trên không áp dụng.

Lưu ý: Nếu _repository.ReportsIQueryable<T> truy vấn đầu tiên sẽ hoạt động; bởi vì EF sẽ xây dựng cây biểu thức một cách chính xác và thực thi SQL thích hợp.

0

Chỉ cần cho sự tò mò vì lợi ích, có bạn đã cố gắng chuyển đổi

from el in _repository.EventLogs 
where !_repository.Reports.Any(p => p.EventLogID == el.EventlogID) 

để

from el in _repository.EventLogs 
where !_repository.Reports.Where(p => p.EventLogID == el.EventlogID).Any(); 

hoặc

from el in _repository.EventLogs 
where !_repository.Reports.Where(p => p.EventLogID == el.EventlogID).Count() > 0; 
+1

không nên là một bình luận? –

+0

Tất cả đều tạo ra cùng một hành vi. –

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