使用EFCore和Linq查询语句封装复杂的查询结果

这里举一个例子,用到了三个实体类,分别是

[Table("t_user")]
public class User
{[Key]public long Id { get; set; }public string UserName { get; set; }public string Password { get; set; }public string Email { get; set; }public List<Role> Roles { get; set; }
}

用户类

[Table("t_role")]
public class Role
{[Key]public long Id { get; set; }public string Name { get; set; }public List<User> Users { get; set; }public List<Authority> Authoritys { get; set; }
}

角色类

[Table("t_user_role")]
public class UserRole
{public long UserId {  get; set; }public long RoleId { get; set; }
}

以及用户和角色的关系表类,这表明用户和角色是多对多的关联关系。
如果要根据用户名查询用户信息以及关联的角色信息,如何实现?这里介绍一下,我见过的3种方法。
1、第一种就是配置用户和角色间的关联关系,在数据库上下文类中加入这么一行代码

protected override void OnModelCreating(ModelBuilder modelBuilder)
{modelBuilder.Entity<User>().HasMany(user => user.Roles).WithMany(role => role.Users).UsingEntity<UserRole>();
}

然后,在接口中使用一行代码,就能得到查询结果

var user = await context.Users.Include(user => user.Roles).Where(user => user.UserName == username).FirstOrDefaultAsync();

这里通过调用Include方法,利用了用户与角色间配置的关联关系,生成的SQL语句如下(数据库使用MySQL)

 SELECT `t0`.`Id`, `t0`.`Email`, `t0`.`Password`, `t0`.`UserName`, `t1`.`RoleId`, `t1`.`UserId`, `t1`.`Id`, `t1`.`Name`FROM (SELECT `t`.`Id`, `t`.`Email`, `t`.`Password`, `t`.`UserName`FROM `t_user` AS `t`WHERE `t`.`UserName` = @__username_0LIMIT 1) AS `t0`LEFT JOIN (SELECT `t2`.`RoleId`, `t2`.`UserId`, `t3`.`Id`, `t3`.`Name`FROM `t_user_role` AS `t2`INNER JOIN `t_role` AS `t3` ON `t2`.`RoleId` = `t3`.`Id`) AS `t1` ON `t0`.`Id` = `t1`.`UserId`ORDER BY `t0`.`Id`, `t1`.`RoleId`, `t1`.`UserId`

这里很明显,用到了2次连接查询并且用到了嵌套子查询。其实,像这种简单的功能,做三张表的左外连接查询就能实现,没必要使用嵌套查询,因此efcore自动生成的SQL语句性能并不是最优的。如果想自己定制SQL语句,又不想直接手写SQL语句,我又尝试了第二种方法。

2、第二种方法的代码如下

var userQuery = from user in context.Usersjoin userRole in context.UserRoles on user.Id equals userRole.UserId into urfrom subUserRole in ur.DefaultIfEmpty()join role in context.Roles on subUserRole.RoleId equals role.Id into rwhere user.UserName == usernameselect new User{Id = user.Id,Password = user.Password,Roles = (from subRole in r select new Role { Name = subRole.Name }).ToList()};
var users= await userQuery.ToListAsync();

这里用到了linq中的连接查询语法,并使用linq中的嵌套查询来封装User类中的Roles集合,生成的SQL语句如下

SELECT `t`.`Id`, `t`.`Password`, `t0`.`RoleId`, `t0`.`UserId`, `t1`.`Name`, `t1`.`Id`FROM `t_user` AS `t`LEFT JOIN `t_user_role` AS `t0` ON `t`.`Id` = `t0`.`UserId`LEFT JOIN LATERAL (SELECT `t2`.`Name`, `t2`.`Id`FROM `t_role` AS `t2`WHERE `t0`.`RoleId` IS NOT NULL AND (`t0`.`RoleId` = `t2`.`Id`)) AS `t1` ON TRUEWHERE `t`.`UserName` = @__username_0ORDER BY `t`.`Id`, `t0`.`RoleId`, `t0`.`UserId`

很明显,这里仍然使用了嵌套查询加连接的方式,性能依旧不高,于是我又想到了第三种方法。

3、第三种方法的代码如下

var userQuery = from user in context.Usersjoin userRole in context.UserRoles on user.Id equals userRole.UserId into urfrom subUserRole in ur.DefaultIfEmpty()join role in context.Roles on subUserRole.RoleId equals role.Id into rfrom subRole in r.DefaultIfEmpty()where user.UserName == usernameselect new { Id = user.Id, Password = user.Password, RoleName = subRole.Name };
var customUsers=await userQuery.ToArrayAsync();
//封装查询结果
var users = (from custUser in customUsersgroup custUser by custUser.Id into uselect new User{Id = u.Key,Password = u.First().Password,Roles = (from subUser in u where subUser.RoleName != null select new Role { Name = subUser.RoleName }).ToList()}).ToArray();

这里仍然用到了linq中的连接查询,不同的是,使用了一个匿名类来保存查询结果。然后,又通过linq中的分组查询和子查询,对数据库的查询结果进行封装,将它保存到了users这个数组里面。生成的SQL语句如下

SELECT `t`.`Id`, `t`.`Password`, `t1`.`Name` AS `RoleName`FROM `t_user` AS `t`LEFT JOIN `t_user_role` AS `t0` ON `t`.`Id` = `t0`.`UserId`LEFT JOIN `t_role` AS `t1` ON `t0`.`RoleId` = `t1`.`Id`WHERE `t`.`UserName` = @__username_0

这里只用到了2次连接查询,没有用到任何嵌套语句,终于看到了自己想要的结果。

说明,想使用efcore定制SQL语句,做性能优化,实现起来还是很复杂的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/25843.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Gradle和Maven都是广泛使用的项目自动化构建工具(二)

Gradle和Maven都是广泛使用的项目自动化构建工具&#xff0c;但它们在多个方面存在差异。以下是关于Gradle和Maven的详细对比&#xff1a; 一、构建脚本语言 Maven&#xff1a;使用XML作为构建脚本语言。XML的语法较为繁琐&#xff0c;不够灵活&#xff0c;对于复杂的构建逻辑…

十大排序

本文将以「 通俗易懂」的方式来描述排序的基本实现。 &#x1f9d1;‍&#x1f4bb;阅读本文前&#xff0c;需要一点点编程基础和一点点数据结构知识 本文的所有代码以cpp实现 文章目录 排序的定义 插入排序 ⭐ &#x1f9d0;算法描述 &#x1f496;具体实现 &#x1f…

LabVIEW硬件与仿真双模式设计液压系统

在实际项目中&#xff0c;结合LabVIEW与液压运动控制器&#xff0c;通过设计两种运行方式&#xff1a;硬件运行和仿真运行&#xff0c;使得系统既能进行实际操作又能进行仿真测试。此设计不仅方便了开发调试&#xff0c;也为教学培训和展示提供了极大的便利。本文将从项目背景、…

OBS与直播伴侣是什么关系,是否需要并用?

OBS相较于直播伴侣&#xff0c;提供了更为丰富和灵活的直播功能。OBS是一个免费开源的视频录制和视频实时交流软件&#xff0c;具有以下优势&#xff1a; 优化直播画面&#xff1a;OBS提供了包括卡通头像、卡通人物&#xff0c;以及美颜、特效、滤镜等多种功能&#xff0c;可以…

力扣2300.咒语和药水的成功对数

力扣2300.咒语和药水的成功对数 排序 二分 对于能整除的数 -1以后一起处理可以在原数组直接修改 class Solution {public:vector<int> successfulPairs(vector<int>& spells, vector<int>& potions, long long success) {sort(potions.begin(),p…

【机器学习】基于卷积LSTM的视频预测

1. 引言 1.1 LSTM是什么 LSTM&#xff08;Long Short-Term Memory&#xff09;是一种特殊的循环神经网络&#xff08;RNN&#xff09;变体&#xff0c;旨在解决传统RNN在处理长序列数据时遇到的梯度消失和梯度爆炸问题。LSTM通过引入门控机制和细胞状态的概念&#xff0c;使得…

QPS,平均时延和并发数

我们当前有两个服务A和B&#xff0c;想要知道哪个服务的性能更好&#xff0c;该用什么指标来衡量呢&#xff1f; 1. 单次请求时延 一种最简单的方法就是使用同一请求体同时请求两个服务&#xff0c;性能越好的服务时延越短&#xff0c;即 R T 返回结果的时刻 − 发送请求的…

【Python教程】4-字符串、列表、字典、元组与集合操作

在整理自己的笔记的时候发现了当年学习python时候整理的笔记&#xff0c;稍微整理一下&#xff0c;分享出来&#xff0c;方便记录和查看吧。个人觉得如果想简单了解一名语言或者技术&#xff0c;最简单的方式就是通过菜鸟教程去学习一下。今后会从python开始重新更新&#xff0…

HTTP参数污染漏洞

HTTP参数污染漏洞 1.HPP漏洞概述2.HPP漏洞利用手段3.参数解析&#xff1a;Flask vs PHP 1.HPP漏洞概述 HTTP参数污染攻击是指通过在HTTP请求中插入多个同名参数&#xff0c;混淆服务器对参数的处理逻辑&#xff0c;进而实现攻击目的。这种攻击可以在URL查询字符串、POST数据和…

AI大模型探索之路-实战篇16:优化决策流程:Agent智能数据分析平台中Planning功能实践

系列篇章&#x1f4a5; AI大模型探索之路-实战篇4&#xff1a;深入DB-GPT数据应用开发框架调研 AI大模型探索之路-实战篇5&#xff1a;探索Open Interpreter开放代码解释器调研 AI大模型探索之路-实战篇6&#xff1a;掌握Function Calling的详细流程 AI大模型探索之路-实战篇7…

MLM之GLM-4-9B:GLM-4-9B的简介、安装和使用方法、案例应用之详细攻略

MLM之GLM-4-9B&#xff1a;GLM-4-9B的简介、安装和使用方法、案例应用之详细攻略 背景痛点&#xff1a;目前主流的大语言模型如GPT-3等&#xff0c;在多轮对话能力、多语言能力、长文本理解能力以及对工具和代码调用能力等方面存在一定限制。 解决方案&#xff1a; >> 在…

现代x86汇编-环境安装

今天端午节&#xff0c;独自在家&#xff0c;翻阅了张银奎老师编写的《现代x86汇编语言程序设计》一书&#xff0c;前言部分说明书中示例代码都是用微软visual C工具编写并使用微软宏汇编&#xff08;著名的MASM&#xff09;编译的&#xff0c;好久没有用微软vc了&#xff0c;假…

详解FedProx:FedAvg的改进版 Federated optimization in heterogeneous networks

FedProx&#xff1a;2020 FedAvg的改进 论文&#xff1a;《Federated Optimization in Heterogeneous Networks》 引用量&#xff1a;4445 源码地址&#xff1a; 官方实现&#xff08;tensorflow&#xff09;https://github.com/litian96/FedProx 几个pytorch实现&#xff1a;…

基于STM32的595级联的Proteus仿真

文章目录 一、595级联1.题目要求2.思路3.仿真图3.1 未仿真时3.2 模式A3.2 模式B3.3 故障模式 二、总结 一、595级联 1.题目要求 STM32单片机&#xff0c;以及三个LED灯对应红黄绿灯&#xff0c;IIC的OLED显示屏&#xff0c;温湿度传感器DHT11&#xff0c;两个独立按键和两个5…

MySQL时间和日期类型详解(零基础入门篇)

目录 1. DATE 2. DATETIME 3. TIMESTAMP 4. TIME 5. YEAR 6. 日期和时间的使用示例 以下SQL语句的测试可以使用命令行&#xff0c;或是使用SQL工具比如MySQL Workbench或SQLynx等。 在 MySQL 中&#xff0c;时间和日期数据类型用于存储与时间相关的数据&#xff0c;如何…

Python数据分析与建模库-02科学计算库Numpy-3.矩阵属性

该视频主要讲述了线性回归算法的核心思想和应用。首先&#xff0c;回顾了线性回归的基本概念&#xff0c;即通过历史数据学习参数&#xff0c;使得参数与特征组合后拟合效果最佳。接着&#xff0c;介绍了误差项的假设和高斯分布的概念&#xff0c;并推导了如何找到使拟合效果最…

重温共射放大电路

1、放大概念 小功率信号变成一个大功率信号&#xff0c;需要一个核心器件做这件事&#xff0c;核心器件的能量由电源提供&#xff0c;通过核心器件用小功率的信号去控制大电源&#xff0c;来实现能量的转换和控制&#xff0c;前提是不能失真&#xff0c;可以用一系列正弦波进行…

Qt定时器

在 Qt 框架中&#xff0c;定时器是一个非常强大和常用的工具&#xff0c;用于定期执行某些任务。Qt 提供了一些类和方法来实现定时功能&#xff0c;其中最常用的是 QTimer 类。 一、QTimer 概述 QTimer 类是 Qt 中实现定时功能的核心类。它提供了一个简单的接口&#xff0c;用…

Running Gradle task ‘assembleDebug‘ Flutter项目

基于Android方面运行Flutter项目一直卡在 Launching lib\main.dart on Android SDK built for x86 in debug mode… Running Gradle task ‘assembleDebug’… 基础原因&#xff1a; 默认存放Gradle插件包的Maven仓库是国外(需VPN) 我的原因&#xff1a; 缺少JDK和缺少Androi…

【Oracle】Oracle导入导出dmp文件

文章目录 前言一、什么是dmp&#xff1f;二、imp/impdp、exp/expdp对比及示例1.区别2.imp/impdp对比及示例a. impb. impbp 3.exp/expdp对比及示例a. expb.expdp 3.其他事项 三、执行导入导出前置条件1.创建角色并授权2.创建目录映射 前言 在工作中&#xff0c;经常会遇到需要备…