LINQKit:在 LINQ to Entities 中嵌套 ExpandableQuery

标签 linq entity-framework-5 linqkit

我一直在尝试合并 LINQKit然而,我在共享数据访问层中遇到了障碍。使用 ExpandableQuery 构造嵌套查询时,表达式解析器无法正确解包 ExpandableQuery 并构造有效的 SQL 查询。抛出的错误如下:

System.NotSupportedException : Unable to create a constant value of type 'Store'. Only primitive types or enumeration types are supported in this context.

通过下面的示例程序,我们可以轻松地重构这个问题,并且它显然与 `table 上的 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 就是您期望执行三角连接的 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 并计算表达式解析器中的嵌套子查询?

最佳答案

您可以尝试的一件事是使用.AsEnumerable。这将阻止直接转换为 SQL,而这正是错误的来源。

在 Main 中尝试以下操作:

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();

关于LINQKit:在 LINQ to Entities 中嵌套 ExpandableQuery,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18346014/

相关文章:

c# - LinqKit 谓词 Or 与 Contains 计算结果为等于

c# - LINQ 按时间段聚合和分组

c# - 使用 Select(...).Any(...) 时,select 的方法运行了多少次?

c# - 检查一个列表是否包含另一个列表中的任何元素

c# - "EntityType has no key defined"异常,尽管键是用 HasKey 定义的

c# - 使用通用 LINQ 表达式调用 Contains 方法的忽略大小写

c# - LINQ to Entities Select with LINQkit 中的调用表达式

c# - 将 IEnumerable<T> 拆分为固定大小的 block (返回 IEnumerable<IEnumerable<T>> ,其中内部序列具有固定长度)

c# - 如何使用 Entity Framework 5 确保幂等数据库插入?

.net - 当我从控制台运行 EF 代码迁移时 - 输入字符串格式不正确错误