我试图用一个额外的列列出所有项目,描述它是否由当前用户拥有。
所以我正在寻找一个生成类似于以下 SQL 的 Linq 查询:
SELECT *,
CASE WHEN
EXISTS (
SELECT NULL FROM OwnedItems
WHERE OwnedItems.UserId = @UserId AND OwnedItems.ItemId = Items.Id
)
THEN 'true'
ELSE 'false'
END AS Owned
FROM Items;
根据互联网以及成功的 LinqPad 实验,此代码应该可以工作。
from item in Items
select new
{
Owned = OwnedItems.Any(own => own.UserId == userId && own.ItemId == item.Id),
Item = item
}
在 LinqPad 中,此代码生成与我想要的完全相同的 SQL。但在我的项目中,它做了一些完全不同的事情。
我的代码是使用 Entity Framework Core 2.1 的 .Net Core 2.1 项目。由于它是一个核心项目,因此我无法在 LinqPad 中直接对其进行测试,因为它尚不受支持。
在我的项目中,此代码会生成一个未过滤的 SELECT 语句来查询每个项目,然后为每个项目单独查询以检查它是否存在于 OwnedItems 表中。像这样:
此查询的 1 个实例运行:
Executed DbCommand (68ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT *
FROM [Items] AS [item]
接下来是数百个这样的查询,需要几秒钟才能运行:
Executed DbCommand (32ms) [Parameters=[@__userId_0='?' (DbType = Int32), @_outer_Id='?' (DbType = Int32)], CommandType='Text', CommandTimeout='30']
SELECT CASE
WHEN EXISTS (
SELECT 1
FROM [OwnedItems] AS [ownedItems]
WHERE ([ownedItems].[UserId] = @__userId_0) AND ([ownedItems].[ItemId] = @_outer_Id))
THEN CAST(1 AS BIT) ELSE CAST(0 AS BIT)
END
一些进一步的信息,也许它会有所帮助:如果我使用同一行作为 where 子句的一部分,它会完美运行。
var q = from item in Items
where OwnedItems.Any(o => o.UserId == userId && o.ItemId == item.Id)
select item;
上面的 linq 产生了这个漂亮的 sql:
SELECT *
FROM [Items] AS [item]
WHERE EXISTS (
SELECT 1
FROM [OwnedItems] AS [o]
WHERE ([o].[UserId] = @__userId_0) AND ([o].[ItemId] = [item].[Id]))
笔记:
上面的代码是手动修改的,所以可能有错别字。请无视他们。
我知道这个特定的查询可以使用左连接和检查空值来完成,但我的实际查询更复杂,我需要(嵌套)存在子句。
喵喔喔
万千封印
相关分类