【问题标题】:Linq generate select with no fromLinq 生成选择,没有来自
【发布时间】:2018-07-11 13:20:15
【问题描述】:

在 sql 中我可以做到这一点

select 'a' as MyColumn

所以,我在 linq 中有一个带有实体框架的查询,它从数据库中获取一些数据,但是,我需要将该查询与一行合并,并且在 sql 中我可以这样做:

select ... from ...
union 
select 'a' as MyColumn

如何使用 linq 生成此查询? 我试着这样做:

var query = (from ... select new {..}).Union(new List<...> { new ...() { MyColumn = 'a' } })

但我猜实体框架不知道如何将内存列表中的内容转换为 sql

我需要得到一个 IQueryable 结果,而不是 List 或其他内存集合,因为我需要在将来将该结果加入其他 sql linq 查询。

【问题讨论】:

  • 你应该可以做到的。看看this answer
  • @RigertaDemiri,这种方法的问题是他们将第一个查询放到内存中的 List 中,然后将一个元素添加到该列表中。我需要保留 IQueryable,而不是在内存中。也许,我没有在问题中说出来。我会更新的。
  • Enumerable.Repeat(new { MyColumn = 'a' }, 1) 适合你吗?
  • @Enigmativity,我会尝试

标签: c# sql entity-framework linq


【解决方案1】:

这是不可能的,你不应该这样做。两者都是出于相同的原因:Entity Framework 将尝试将整个 LINQ 语句转换为 SQL,包括本地列表 (new List&lt;...&gt;)。

不可能的原因是 EF 无法将 C# 对象转换为 SQL 构造。

你不应该这样做的原因是它非常浪费:你用 C# 代码构建列表,EF(如果可以的话)将其转换为 SQL 语句,数据库运行 SQL 语句并将其转换为结果集,EF 接收结果集并将其转换为您最初提供的列表。

为了演示,我将展示如果您使用 EF 知道如何转换为 SQL 的原始值列表来执行此操作会发生什么:

var ints = Enumerable.Range(1,5);
var res = Products.Select(c => c.Id).Union(ints).ToList();

这将产生以下 SQL 语句:

SELECT 
    [Distinct1].[C1] AS [C1]
    FROM ( SELECT DISTINCT 
        [UnionAll5].[ProductId] AS [C1]
        FROM  (SELECT 
            [Extent1].[ProductId] AS [ProductId]
            FROM [dbo].[Product] AS [Extent1]
        UNION ALL
            SELECT 
            1 AS [C1]
            FROM  ( SELECT 1 AS X ) AS [SingleRowTable1]
        UNION ALL
            SELECT 
            2 AS [C1]
            FROM  ( SELECT 1 AS X ) AS [SingleRowTable2]
        UNION ALL
            SELECT 
            3 AS [C1]
            FROM  ( SELECT 1 AS X ) AS [SingleRowTable3]
        UNION ALL
            SELECT 
            4 AS [C1]
            FROM  ( SELECT 1 AS X ) AS [SingleRowTable4]
        UNION ALL
            SELECT 
            5 AS [C1]
            FROM  ( SELECT 1 AS X ) AS [SingleRowTable5]) AS [UnionAll5]
    )  AS [Distinct1]

如您所见,EF 为列表中的每个元素生成了一个 SingleRowTablex 条目,以使用来自实际查询的 id 为 UNION 构建一个“临时表”。

结论:只需从数据库中查询您需要的内容,然后添加到结果中即可。这样做很容易:

(from ... select new {..})
    .AsEnumerable() // continue in memory
    .Union(...)

【讨论】:

  • 我应该提一下,在这种情况下,EF-core 将自动切换到客户端评估,即它将在客户端 (C#) 代码中运行Union。我假设您在 EF6 中工作,因为当仅标记 [entity-framework] 时,这似乎仍然是“默认”。
  • 这正是我所需要的,即使实体框架使用联合创建了该选择。
猜你喜欢
  • 2013-10-11
  • 1970-01-01
  • 1970-01-01
  • 2021-12-27
  • 2021-09-10
  • 1970-01-01
  • 2022-08-05
  • 2012-09-16
  • 1970-01-01
相关资源
最近更新 更多