«Не поддерживается преобразование в SQL» после десериализации выражения IQueryable

Я работаю над созданием JsonConverter для JSON.NET, способного сериализовать и десериализовать выражения (System.Linq .Выражения). Я выполнил последние 5% или около того работы, и у меня возникли проблемы с запуском запроса LINQ-to-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-to-SQL. TestQuerySourceявляется реализацией System.Data.Linq.DataContext. Bundle, BundleItem, Product— все сущности LINQ-to-SQL, украшенные TableAttributeи другими атрибутами сопоставления. Соответствующие им свойства контекста данных — это все свойства Table , как обычно. Другими словами, здесь нет ничего эффектно примечательного.

Однако, когда я пытаюсь выполнить запрос после десериализации выражения, я получаю следующую ошибку:

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}

Проблема возникает, когда не примитивно типизированное свойство анонимного тип должен быть доступен. В этом случае доступ к свойству biосуществляется для доступа к свойству BundleItem's 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()}
6
задан Daniel Schaffer 6 April 2012 в 00:15
поделиться