我正在爲能夠序列化和反序列化表達式(System.Linq.Expressions)的JSON.NET創建JsonConverter。我下降到最後5%左右的工作,並且遇到問題能夠運行從反序列化表達式生成的LINQ-to-SQL查詢。反編譯IQueryable表達式後「沒有支持的轉換爲SQL」
這裏是表達:
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;
這是LINQ到SQL一個非常簡單的分組查詢。 TestQuerySource
是System.Data.Linq.DataContext
的實現。 Bundle
,BundleItem
,Product
,都是用TableAttribute
和其他其他映射屬性裝飾的LINQ-to-SQL實體。它們的相應datacontext屬性都是正常的Table<T>
屬性。換句話說,這裏沒有什麼特別值得注意的。
然而,當我試圖表達的反序列化後,運行查詢,我得到以下錯誤:
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.
我明白這意味着什麼表達是做不能轉換通過到SQL LINQ-to-SQL查詢提供程序。看起來它與創建一個匿名類型作爲查詢的一部分有關,例如作爲連接語句的一部分。這個假設是通過比較原始和反序列化表現形式的字符串表示支持:
原件(工作):
{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}
反序列化(碎):
{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}
這個問題似乎發生在一個非原始類型的p需要訪問匿名類型的roperty。在這種情況下,bi
屬性正在訪問,以獲得BundleItem
的ProductID
屬性。
我無法弄清楚什麼區別會是 - 爲什麼訪問原始表達式中的屬性可以正常工作,但不是反序列化的表達式。
我猜這個問題與某些有關匿名類型在序列化期間丟失的信息有關,但我不知道在哪裏尋找它,甚至找什麼。
其他例子:
值得注意的是簡單的表情像這樣的做工精細:
Expression<Func<TestQuerySource, Category>> expression = db => db.Categories.First();
即使做分組(不含加盟)的作品,以及:
Expression<Func<TestQuerySource, Int32>> expression = db => db.Categories.GroupBy(c => c.ID).First().Key;
簡單加入工作:
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();
選擇一個匿名類型的作品:
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();
下面是最後一個例子中的字符串表示:
原文:
{db => db.BundleItems
.Join(db.Products,
bi => bi.ProductID,
p => p.ID,
(bi, p) => new <>f__AnonymousType0`2(a = bi, b = p))
.First()}
反序列化:
{db => db.BundleItems
.Join(db.Products,
bi => bi.ProductID,
p => p.ID,
(bi, p) => new <>f__AnonymousType0`2(bi, p))
.First()}
出於好奇,這是基於InterLinq? – 2012-04-05 21:04:21
不,我直到我已經深入瞭解有些項目正在爲WCF做這些事情之後才意識到......但我也不想處理與此相關的任何WCF。 – 2012-04-05 21:06:16
是的,他們做的系列化的東西非常好。它幾乎從WCF的東西中彈出。當你進入IQueryable實現時,WCF只會進入圖片。它相當乾淨地移植到Silverlight。我懷疑爲JSON.NET換出XML可能也是相對直截了當的。 FWIW;) – 2012-04-05 21:13:08