LINQKit: развертывание расширяемого запроса в LINQ для объектов

Я пытаюсь включить LINQKit в общий уровень доступа к данным, однако я попал в блокпост. При построении вложенного запроса с помощью ExpandableQuery, синтаксический анализатор выражений не может правильно развернуть ExpandableQuery и построить действительный SQL-запрос. Выдающаяся ошибка читает:

System.NotSupportedException: Невозможно создать постоянное значение типа "Сохранить". В этом контексте поддерживаются только примитивные типы или типы перечислений.

С помощью следующей примерной программы мы можем легко восстановить эту проблему, и она явно изолирована от вызова AsExpandable() в таблице.

class Program
{
    static void Main(string[] args)
    {
        Database.SetInitializer<MyContext>(null);
        var cs = MY_CONNECTION_STRING;
        var context = new MyContext(cs);

        var table = (IQueryable<Store>)context.Set<Store>();
        var q = table
            .AsExpandable()
            .Select(t => new {Id = t.StoreId, less = table.Where(tt => tt.StoreId > t.StoreId) })
            .Take(1)
            .ToArray();
    }
}

public class MyContext : DbContext
{
    public MyContext(string connection) : base(connection) {}

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Store>();
        base.OnModelCreating(modelBuilder);
    }
}

[Table("stores")]
public class Store
{
    [Key]
    public int StoreId { get; set; }
}

Когда вы удаляете вызов AsExpandable(), генерируемый SQL - это то, что вы ожидаете выполнить треугольное соединение:

SELECT 
[Project1].[StoreId] AS [StoreId], 
[Project1].[C1] AS [C1], 
[Project1].[StoreId1] AS [StoreId1]
FROM ( SELECT 
    [Limit1].[StoreId] AS [StoreId], 
    [Extent2].[StoreId] AS [StoreId1], 
    CASE WHEN ([Extent2].[StoreId] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1]
    FROM   (SELECT TOP (1) [c].[StoreId] AS [StoreId]
        FROM [dbo].[stores] AS [c] ) AS [Limit1]
    LEFT OUTER JOIN [dbo].[stores] AS [Extent2] ON [Extent2].[StoreId] > [Limit1].[StoreId]
)  AS [Project1]
ORDER BY [Project1].[StoreId] ASC, [Project1].[C1] ASC

Однако, когда вы включаете AsExpandable(), Entity Framework вытаскивает всю таблицу магазинов в память, перед сбоем с ошибкой "Невозможно создать постоянную".

Есть ли какие-либо известные обходные пути, чтобы заставить LINQKit развернуть ExpandableQuery и оценить вложенный подзапрос в выражающем парсере?

Ответ 1

Одна вещь, которую вы могли бы попробовать - использовать .AsEnumerable. Это предотвратит прямой перевод на SQL, откуда приходит ваша ошибка.

Попробуйте выполнить следующее на главной странице:

var table = (IQueryable<Store>)context.Set<Store>();
var q = table
    .AsEnumerable()
    .Select(t => new {Id = t.StoreId, less = table.Where(tt => tt.StoreId > t.StoreId) })
    .Take(1)
    .ToArray();

Ответ 2

Это не связано с Linqkit. Это исключение EF, которое вы всегда получаете, когда используете объект, где разрешено только примитивное значение.

Я думаю, что tt является объектом Store. Этот объект не может быть преобразован в SQL. Поэтому сначала поместите идентификатор tt.StoreId в переменную и используйте переменную в запросе.