EFCore里面有一些方法可以方便的做关联查询,比如include方法,但是生成的SQL语句不尽人意,性能并不是最优的,想做内连接还是外连接,也没法用这个方法来掌控,要想完全掌控SQL语句,就需要用linq表达式来写查询逻辑
var query = from user in context.Users
join userRole in context.UserRoles on user.Id equals userRole.UserId into userRoles
from subUserRole in userRoles.DefaultIfEmpty()
join role in context.Roles on subUserRole.RoleId equals role.Id into roles
from subRole in roles.DefaultIfEmpty()
where user.UserName == username
select new {
user.Id, user.Password, RoleId=subRole.Id as long? };
这里面用到了左外连接查询,也就是查左表中所有数据,查右表中符合连接条件的数据,subRole属于右表的对象,所以可能是空的,如果直接把subRole.Id赋值给RoleId,会导致运行的时候报错,所以需要用as long?把RoleId的类型声明为可以保存null值,才能避免这种报错。
封装好了查询逻辑,就可以执行查询
var custTypes = await query.ToArrayAsync();
下一步就是封装查询结果
var custUser = custTypes.GroupBy(cust => cust.Id)
.Select(group => new {
Id = group.Key,
Password = group.Single().Password,
RoleIds = group.Where(cust => cust.RoleId!=null).Select(cust => cust.RoleId) })
.SingleOrDefault();
由于存在一对多的集合,这里使用了分组查询,加嵌套子查询来封装查询结果,最后得到了想要的数据格式。