Reputation: 2065
I'm currently using Linq to SQL within ASP.NET Core 1.0 with the npgsql PostgreSQL adapter.
I have the following LINQ query which is expected to return a list of type 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);
The intention of this code is to find all Devices that a certain user is allowed to access by doing a Where
against the UserGroupMembershipList
, and then joining the rest of the tables in until a list of Device
is reached.
The relationship between the entities is :
UserGroupMembershipList
-(many to one)-> UserGroup
-(one to many)-> UserGroupAccessList
-(many to one)-> DeviceGroup
-(one to many)-> Device
UserGroupAccessList
is an ACL that acts as a many to many join table between UserGroup
and DeviceGroup
.
This then generates the SQL query:
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")
Which in turn produces the error
An exception occurred in the database while iterating the results of a query. Npgsql.NpgsqlException: 42703: column ugml.UserGroupId does not exist
Which appears to be because the SQL query is for some reason doing a SELECT FROM "Device" AS ugml
instead of SELECT FROM "UserGroupMembershipList" AS ugml
. Additionally the where clause appears to be incorrect because of this.
Am I doing anything wrong when it comes to the Linq query? Are there any other ways to go about what I'm trying to accomplish that might avoid this error?
EDIT:
I have found a work around, although it is less than ideal.
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);
This makes the query join the tables after the WHERE
, and then return the entire result set as a List
, from which standard Linq can operate on it in memory. It's less than ideal because I need to further refine the query afterwards, so much more data is transferred in comparison to doing everything in the database.
Upvotes: 1
Views: 954
Reputation: 9499
Why not issue a single Select query and project out the results?
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();
Try the above query and let us know if you see any issues.
If you still see the issues, i suspect that the npgsql adapter still has some wrinkles around the adapter, since I have followed some similar bugs in the npgsql branch in github.
Upvotes: 2