LINQ to SQL [npgsql] 从 SelectMany 生成不正确的查询
LINQ to SQL [npgsql] Generating incorrect query from SelectMany
我目前正在 ASP.NET Core 1.0 中使用 Linq to SQL 和 npgsql PostgreSQL 适配器。
我有以下 LINQ 查询,它预期 return 类型 Device
的列表
var devices = DeviceConfigurationDbContext.UserGroupMembershipList
.AsNoTracking()
.Where(ugml => ugml.UserId == currentUser.Id)
.Select(ugml => ugml.UserGroup)
.SelectMany(ug => ug.UserGroupAccessList)
.Select(uga => uga.DeviceGroup)
.SelectMany(dg => dg.Devices);
此代码的目的是通过对 UserGroupMembershipList
执行 Where
来查找允许特定用户访问的所有设备,然后加入其余的 table 直到到达 Device
的列表。
实体之间的关系是:
UserGroupMembershipList
-(多对一)-> UserGroup
-(一对多)-> UserGroupAccessList
-(多对一)-> DeviceGroup
- (一对多)-> Device
UserGroupAccessList
是一个 ACL,充当 UserGroup
和 DeviceGroup
之间的多对多连接 table。
然后生成 SQL 查询:
SELECT "ugml"."Id", "ugml"."DeviceGroupId", "d"."DeviceGroupId", "d"."Name", "uga.DeviceGroup"."Id"
FROM "Device" AS "ugml"
INNER JOIN "UserGroup" AS "ugml.UserGroup" ON "ugml"."UserGroupId" = "ugml.UserGroup"."Id"
CROSS JOIN "UserGroupAccess" AS "uga"
INNER JOIN "DeviceGroup" AS "uga.DeviceGroup" ON "uga"."DeviceGroupId" = "uga.DeviceGroup"."Id"
CROSS JOIN "Device" AS "d"
WHERE ("ugml"."UserId" = @__currentUser_Id_0) AND ("ugml.UserGroup"."Id" = "ugml"."UserGroupId")
这又会产生错误
An exception occurred in the database while iterating the results of a
query. Npgsql.NpgsqlException: 42703: column ugml.UserGroupId does not
exist
这似乎是因为 SQL 查询出于某种原因执行 SELECT FROM "Device" AS ugml
而不是 SELECT FROM "UserGroupMembershipList" AS ugml
。此外,where 子句似乎因此不正确。
关于 Linq 查询,我做错了什么吗?是否有任何其他方法可以解决我正在尝试完成的问题,从而避免此错误?
编辑:
我找到了变通方法,尽管它不太理想。
var devices = (await DeviceConfigurationDbContext.UserGroupMembershipList
.AsNoTracking()
.Where(ugml => ugml.UserId == currentUser.Id)
.Include(o => o.UserGroup)
.ThenInclude(o => o.UserGroupAccessList)
.ThenInclude(o => o.DeviceGroup)
.ThenInclude(o => o.Devices)
.ToListAsync())
.Select(ugml => ugml.UserGroup)
.SelectMany(ug => ug.UserGroupAccessList)
.Select(uga => uga.DeviceGroup)
.SelectMany(dg => dg.Devices);
这使得查询在WHERE
之后加入tables,然后return整个结果集作为一个List
,从中标准Linq可以操作在记忆中。这不太理想,因为之后我需要进一步细化查询,与在数据库中执行所有操作相比,传输的数据要多得多。
为什么不发出单个 Select 查询并投影出结果?
var devices = await DeviceConfigurationDbContext.UserGroupMembershipList
.AsNoTracking()
.Where(ugml => ugml.UserId == currentUser.Id)
.Include(o => o.UserGroup)
.ThenInclude(o => o.UserGroupAccessList)
.ThenInclude(o => o.DeviceGroup)
.ThenInclude(o => o.Devices)
.SelectMany(ugml => ugml.UserGroup.UserGroupAccessLists
.Select(ugal => ugal.DeviceGroup.Devices)
.ToListAsync();
试试上面的查询,如果发现任何问题请告诉我们。
如果您仍然看到问题,我怀疑 npgsql 适配器周围仍然存在一些问题,因为我在 github.
的 npgsql 分支中跟踪了一些类似的错误
我目前正在 ASP.NET Core 1.0 中使用 Linq to SQL 和 npgsql PostgreSQL 适配器。
我有以下 LINQ 查询,它预期 return 类型 Device
var devices = DeviceConfigurationDbContext.UserGroupMembershipList
.AsNoTracking()
.Where(ugml => ugml.UserId == currentUser.Id)
.Select(ugml => ugml.UserGroup)
.SelectMany(ug => ug.UserGroupAccessList)
.Select(uga => uga.DeviceGroup)
.SelectMany(dg => dg.Devices);
此代码的目的是通过对 UserGroupMembershipList
执行 Where
来查找允许特定用户访问的所有设备,然后加入其余的 table 直到到达 Device
的列表。
实体之间的关系是:
UserGroupMembershipList
-(多对一)-> UserGroup
-(一对多)-> UserGroupAccessList
-(多对一)-> DeviceGroup
- (一对多)-> Device
UserGroupAccessList
是一个 ACL,充当 UserGroup
和 DeviceGroup
之间的多对多连接 table。
然后生成 SQL 查询:
SELECT "ugml"."Id", "ugml"."DeviceGroupId", "d"."DeviceGroupId", "d"."Name", "uga.DeviceGroup"."Id"
FROM "Device" AS "ugml"
INNER JOIN "UserGroup" AS "ugml.UserGroup" ON "ugml"."UserGroupId" = "ugml.UserGroup"."Id"
CROSS JOIN "UserGroupAccess" AS "uga"
INNER JOIN "DeviceGroup" AS "uga.DeviceGroup" ON "uga"."DeviceGroupId" = "uga.DeviceGroup"."Id"
CROSS JOIN "Device" AS "d"
WHERE ("ugml"."UserId" = @__currentUser_Id_0) AND ("ugml.UserGroup"."Id" = "ugml"."UserGroupId")
这又会产生错误
An exception occurred in the database while iterating the results of a query. Npgsql.NpgsqlException: 42703: column ugml.UserGroupId does not exist
这似乎是因为 SQL 查询出于某种原因执行 SELECT FROM "Device" AS ugml
而不是 SELECT FROM "UserGroupMembershipList" AS ugml
。此外,where 子句似乎因此不正确。
关于 Linq 查询,我做错了什么吗?是否有任何其他方法可以解决我正在尝试完成的问题,从而避免此错误?
编辑:
我找到了变通方法,尽管它不太理想。
var devices = (await DeviceConfigurationDbContext.UserGroupMembershipList
.AsNoTracking()
.Where(ugml => ugml.UserId == currentUser.Id)
.Include(o => o.UserGroup)
.ThenInclude(o => o.UserGroupAccessList)
.ThenInclude(o => o.DeviceGroup)
.ThenInclude(o => o.Devices)
.ToListAsync())
.Select(ugml => ugml.UserGroup)
.SelectMany(ug => ug.UserGroupAccessList)
.Select(uga => uga.DeviceGroup)
.SelectMany(dg => dg.Devices);
这使得查询在WHERE
之后加入tables,然后return整个结果集作为一个List
,从中标准Linq可以操作在记忆中。这不太理想,因为之后我需要进一步细化查询,与在数据库中执行所有操作相比,传输的数据要多得多。
为什么不发出单个 Select 查询并投影出结果?
var devices = await DeviceConfigurationDbContext.UserGroupMembershipList
.AsNoTracking()
.Where(ugml => ugml.UserId == currentUser.Id)
.Include(o => o.UserGroup)
.ThenInclude(o => o.UserGroupAccessList)
.ThenInclude(o => o.DeviceGroup)
.ThenInclude(o => o.Devices)
.SelectMany(ugml => ugml.UserGroup.UserGroupAccessLists
.Select(ugal => ugal.DeviceGroup.Devices)
.ToListAsync();
试试上面的查询,如果发现任何问题请告诉我们。
如果您仍然看到问题,我怀疑 npgsql 适配器周围仍然存在一些问题,因为我在 github.
的 npgsql 分支中跟踪了一些类似的错误