Tôi đang làm việc về việc tạo một JsonConverter cho JSON.NET có khả năng tuần tự hóa và deserializing biểu thức (System.Linq.Expressions). Tôi đang xuống đến 5% cuối cùng của công việc, và tôi đang gặp vấn đề có thể chạy một truy vấn LINQ-to-SQL được tạo ra từ biểu thức deserialized."Không hỗ trợ dịch sang SQL" sau khi deserializing biểu thức IQueryable
Dưới đây là các biểu hiện:
Expression<Func<TestQuerySource, Bundle>> expression = db => (
from b in db.Bundles
join bi in db.BundleItems on b.ID equals bi.BundleID
join p in db.Products on bi.ProductID equals p.ID
group p by b).First().Key;
Đây là câu hỏi nhóm khá đơn giản trong LINQ-to-SQL. TestQuerySource
là triển khai System.Data.Linq.DataContext
. Bundle
, BundleItem
, Product
, là tất cả các thực thể LINQ-to-SQL được trang trí với TableAttribute
và các thuộc tính ánh xạ khác. Các thuộc tính datacontext tương ứng của chúng là tất cả các thuộc tính Table<T>
như bình thường. Nói cách khác, không có gì đáng chú ý đáng chú ý ở đây.
Tuy nhiên, khi tôi cố gắng để chạy các truy vấn sau khi các biểu hiện đã được deserialized, tôi nhận được lỗi sau:
System.Reflection.TargetInvocationException:
Exception has been thrown by the target of an invocation. --->
System.NotSupportedException: The member '<>f__AnonymousType0`2[Bundle,BundleItem].bi' has no supported translation to SQL.
Tôi hiểu rằng điều này có nghĩa rằng một cái gì đó biểu hiện đang làm không thể được dịch sang SQL bởi nhà cung cấp truy vấn LINQ-to-SQL. Dường như nó có liên quan đến việc tạo một kiểu ẩn danh như là một phần của truy vấn, giống như một phần của câu lệnh nối. Giả định này được hỗ trợ bằng cách so sánh chuỗi đại diện của các biểu thức ban đầu và deserialized:
gốc (làm việc):
{db => db.Bundles
.Join(db.BundleItems,
b => b.ID,
bi => bi.BundleID,
(b, bi) => new <>f__AnonymousType0`2(b = b, bi = bi))
.Join(db.Products,
<>h__TransparentIdentifier0 => <>h__TransparentIdentifier0.bi.ProductID,
p => p.ID,
(<>h__TransparentIdentifier0, p) =>
new <>f__AnonymousType1`2(<>h__TransparentIdentifier0 = <>h__TransparentIdentifier0, p = p))
.GroupBy(<>h__TransparentIdentifier1 =>
<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.b,
<>h__TransparentIdentifier1 => <>h__TransparentIdentifier1.p)
.First().Key}
deserialized (bị hỏng):
{db => db.Bundles
.Join(db.BundleItems,
b => b.ID,
bi => bi.BundleID,
(b, bi) => new <>f__AnonymousType0`2(b, bi))
.Join(db.Products,
<>h__TransparentIdentifier0 => <>h__TransparentIdentifier0.bi.ProductID,
p => p.ID,
(<>h__TransparentIdentifier0, p) => new <>f__AnonymousType1`2(<>h__TransparentIdentifier0, p))
.GroupBy(<>h__TransparentIdentifier1 =>
<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.b,
<>h__TransparentIdentifier1 => <>h__TransparentIdentifier1.p)
.First().Key}
Sự cố có vẻ xảy ra khi một tệp không được nhập chính xác roperty của một loại vô danh cần được truy cập. Trong trường hợp này, thuộc tính bi
đang được truy cập để truy cập thuộc tính ProductID
của BundleItem
.
Điều tôi không thể hiểu được là sự khác biệt sẽ là gì - tại sao việc truy cập thuộc tính trong biểu thức ban đầu sẽ hoạt động tốt, nhưng không có trong biểu thức deserialized.
Tôi đoán sự cố có liên quan đến một số loại thông tin về loại ẩn danh bị mất trong quá trình tuần tự hóa, nhưng tôi không chắc chắn nên tìm ở đâu hoặc thậm chí tìm kiếm gì.
Các ví dụ khác:
Điều đáng chú ý là biểu thức đơn giản như thế này tốt một công việc:
Expression<Func<TestQuerySource, Category>> expression = db => db.Categories.First();
Ngay cả làm nhóm (không tham gia) hoạt động cũng như:
Expression<Func<TestQuerySource, Int32>> expression = db => db.Categories.GroupBy(c => c.ID).First().Key;
Tham gia đơn giản hoạt động:
Expression<Func<TestQuerySource, Product>> expression = db => (
from bi in db.BundleItems
join p in db.Products on bi.ProductID equals p.ID
select p).First();
Chọn một loại vô danh hoạt động:
Expression<Func<TestQuerySource, dynamic>> expression = db => (
from bi in db.BundleItems
join p in db.Products on bi.ProductID equals p.ID
select new { a = bi, b = p }).First();
Sau đây là các cơ quan đại diện chuỗi các ví dụ cuối cùng:
gốc:
{db => db.BundleItems
.Join(db.Products,
bi => bi.ProductID,
p => p.ID,
(bi, p) => new <>f__AnonymousType0`2(a = bi, b = p))
.First()}
deserialized:
{db => db.BundleItems
.Join(db.Products,
bi => bi.ProductID,
p => p.ID,
(bi, p) => new <>f__AnonymousType0`2(bi, p))
.First()}
Chỉ vì tò mò là điều này dựa trên InterLinq? –
Không. Tôi đã không nhận ra cho đến sau khi tôi đã nhận được khá sâu rằng đã có dự án làm điều này cho WCF ... nhưng tôi cũng không muốn phải đối phó với bất cứ điều gì WCF liên quan cho việc này. –
Vâng, công cụ tuần tự hóa mà họ đã làm là khá hay. Nó khá nhiều bật ra từ các công cụ WCF. WCF thực sự chỉ nhập vào hình ảnh khi bạn nhận được vào các triển khai IQueryable. Nó được chuyển đến Silverlight khá sạch. Tôi nghi ngờ hoán đổi XML cho JSON.NET cũng có thể tương đối thẳng về phía trước. FWIW;) –