I am quite new to entity framework so I am confused now. I have these two queries:
var usersQuery =
from role in this.dbContext.Set<Model.ApplicationRole>()
join ru in dbContext.Set<Model.ApplicationRoleUser>() on role.Id equals ru.ApplicationRoleId into rus
from ru in rus.DefaultIfEmpty()
join user in dbContext.Set<Model.User>() on ru.UserId equals user.Id into users
from user in users.DefaultIfEmpty()
where
(ru != null && ru.ApplicationId == application.Id)
&& (roleId == null || ru.ApplicationRoleId == roleId.Value)
group role by user into grps
select
new RoleActor
{
Actor =
new Actor
{
AccountName = grps.Key.AccountName,
DisplayName =
(grps.Key.DisplayName ?? string.Empty) != string.Empty
? grps.Key.DisplayName
: grps.Key.CommonName,
DomainName = grps.Key.DomainName,
Email = grps.Key.Email ?? string.Empty,
CompanyCode = grps.Key.CompanyCode,
AdGuid = grps.Key.AdGuid,
CommonName = grps.Key.CommonName
},
Type = Model.ActorType.User,
RoleNames = grps.Select(role => role.Name).ToList()
};
var groupsQuery =
from role in this.dbContext.Set<Model.ApplicationRole>()
join rg in dbContext.Set<Model.ApplicationRoleGroup>() on role.Id equals rg.ApplicationRoleId into rgs
from rg in rgs.DefaultIfEmpty()
join @group in dbContext.Set<Model.Group>() on rg.GroupId equals @group.Id into groups
from @group in groups.DefaultIfEmpty()
where
(rg != null && rg.ApplicationId == application.Id)
&& (roleId == null || rg.ApplicationRoleId == roleId.Value)
group role by @group into grps
select
new RoleActor
{
Actor =
new Actor
{
AccountName = grps.Key.AccountName,
DisplayName =
(grps.Key.DisplayName ?? string.Empty) != string.Empty
? grps.Key.DisplayName
: grps.Key.CommonName,
DomainName = grps.Key.DomainName,
Email = string.Empty,
CompanyCode = string.Empty,
AdGuid = grps.Key.AdGuid,
CommonName = grps.Key.CommonName
},
Type = Model.ActorType.Group,
RoleNames = grps.Select(role => role.Name).ToList()
};
I need to union these two queries. But when I try to use extension method Union, I get exception:
The 'Distinct' operation cannot be applied to the collection ResultType of the specified argument. Parameter name: argument
I wanted to concat queries and then do something like:
queryConcatResult.GroupBy(x => x.Key).Select(x => x.FirstOrDefault())
However when I use method Concat, I get exception:
The nested query is not supported. Operation1='UnionAll' Operation2='MultiStreamNest'
I will be grateful for any hint.
It's not possible (at least with EF) to perform union or concat of queries that contain nested collection (for instance the result of group by
or RoleNames
as in your case).
The solution is to remove the grouping from the base queries, create uniform projection, concat and then do the grouping.
Something like this:
(1)
var usersQuery =
from user in dbContext.Set<Model.User>()
join ru in dbContext.Set<Model.ApplicationRoleUser>() on user.Id equals ru.UserId
join role in this.dbContext.Set<Model.ApplicationRole>() on ru.ApplicationRoleId equals role.Id
where ru.ApplicationId == application.Id
&& (roleId == null || ru.ApplicationRoleId == roleId.Value)
select new
{
Actor = new Actor
{
AccountName = user.AccountName,
DisplayName = (user.DisplayName ?? "") != "" ? user.DisplayName : user.CommonName,
DomainName = user.DomainName,
Email = user.Email ?? "",
CompanyCode = user.CompanyCode,
AdGuid = user.AdGuid,
CommonName = user.CommonName
},
Type = Model.ActorType.User,
Role = role,
};
(2)
var groupsQuery =
from @group in dbContext.Set<Model.Group>()
join rg in dbContext.Set<Model.ApplicationRoleGroup>() on @group.Id equals rg.GroupId
join role in this.dbContext.Set<Model.ApplicationRole>() on rg.ApplicationRoleId equals role.Id
where rg.ApplicationId == application.Id
&& (roleId == null || rg.ApplicationRoleId == roleId.Value)
select new
{
Actor = new Actor
{
AccountName = @group.AccountName,
DisplayName = (@group.DisplayName ?? "") != "" ? @group.DisplayName : @group.CommonName,
DomainName = @group.DomainName,
Email = "",
CompanyCode = "",
AdGuid = @group.AdGuid,
CommonName = @group.CommonName
},
Type = Model.ActorType.Group,
Role = role,
};
(3)
var actorsQuery =
from a in usersQuery.Concat(groupsQuery)
group a by new { a.Actor, a.Type } into g
select new RoleActor
{
Actor = g.Key.Actor,
Type = g.Key.Type,
RoleNames = g.Select(a => a.Role.Name).ToList()
};
Side note: Although using string.Empty
is a good programming practice, you'd better avoid it in EF queries because EF does not recognize it as constant and generates additional SQL query parameters.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.