05-OQL查询语言详解

news/2025/11/29 13:43:40/文章来源:https://www.cnblogs.com/znlgis/p/19286243

第五章:OQL查询语言详解

5.1 OQL概述

5.1.1 什么是OQL

OQL(ORM Query Language)是SOD框架独创的ORM查询语言,它的设计目标是:

  1. 接近SQL语法:让熟悉SQL的开发者无缝上手
  2. 类型安全:在编译期发现错误,而不是运行时
  3. 数据库无关:一套代码适配多种数据库
  4. 链式调用:流畅的API设计,代码更易读

5.1.2 OQL vs LINQ

特性 OQL LINQ
语法风格 类SQL 函数式/查询式
学习曲线 低(熟悉SQL即可) 中等
延迟执行 调用ToList时执行 延迟执行
SQL可控性 中等
表达式能力 基础 强大
编译时检查 支持 支持

5.1.3 OQL的组成

OQL对象 = From子句 + [Join子句] + Select子句 + [Where子句] + [GroupBy子句] + [Having子句] + [OrderBy子句]

5.2 OQL基本语法

5.2.1 From子句

// 创建实体对象
UserEntity user = new UserEntity();// From是OQL的起点
var oql = OQL.From(user)  // 指定查询的实体.Select()              // SELECT *.END;                  // 结束构建// 多实体From(用于联合查询)
OrderEntity order = new OrderEntity();
var oql2 = OQL.From(order, user).Select().END;

5.2.2 Select子句

UserEntity user = new UserEntity();// SELECT * (查询所有字段)
var oql1 = OQL.From(user).Select().END;// 选择特定字段
var oql2 = OQL.From(user).Select(user.ID, user.Name, user.Email).END;// 使用数组形式
var oql3 = OQL.From(user).Select(new object[] { user.ID, user.Name }).END;

5.2.3 Where子句基础

UserEntity user = new UserEntity();
user.Status = 1;// 方式1:使用实体属性值作为条件
var oql1 = OQL.From(user).Select().Where(user.Status)  // WHERE Status = 1.END;// 方式2:多个条件(AND关系)
user.Name = "张三";
var oql2 = OQL.From(user).Select().Where(user.Status, user.Name)  // WHERE Status=1 AND Name='张三'.END;

5.2.4 OrderBy子句

UserEntity user = new UserEntity();// 升序
var oql1 = OQL.From(user).Select().OrderBy(user.ID)  // ORDER BY ID ASC.END;// 降序
var oql2 = OQL.From(user).Select().OrderBy(user.ID, "desc")  // ORDER BY ID DESC.END;// 多字段排序
var oql3 = OQL.From(user).Select().OrderBy(order => order.Asc(user.Status).Desc(user.CreateTime)).END;
// ORDER BY Status ASC, CreateTime DESC// 使用Lambda表达式
var oql4 = OQL.From(user).Select().OrderBy(o => o.Desc(user.ID)).END;

5.2.5 END属性

// END是必须的,表示OQL构建完成
var oql = OQL.From(user).Select().Where(user.ID).OrderBy(user.Name).END;  // 返回OQL对象// END之后可以调用其他方法
oql.Limit(10, 1);  // 分页
oql.TopCount = 5;  // TOP N

5.3 条件表达式(OQLCompare)

5.3.1 使用Lambda表达式构建条件

UserEntity user = new UserEntity();// 基本比较
var oql = OQL.From(user).Select().Where(cmp => cmp.Property(user.Name) == "张三").END;// 多个条件
var oql2 = OQL.From(user).Select().Where(cmp => cmp.Property(user.Status) == 1 & cmp.Property(user.Age) >= 18).END;

5.3.2 比较运算符

// 等于
cmp.Property(user.Name) == "张三"
cmp.EqualValue(user.Name)  // 使用实体属性当前值// 不等于
cmp.Property(user.Status) != 0// 大于、小于
cmp.Property(user.Age) > 18
cmp.Property(user.Age) < 60
cmp.Property(user.Age) >= 18
cmp.Property(user.Age) <= 60// LIKE模糊查询
cmp.Comparer(user.Name, "like", "张%")      // 以"张"开头
cmp.Comparer(user.Name, "like", "%三")      // 以"三"结尾
cmp.Comparer(user.Name, "like", "%小%")     // 包含"小"// IS NULL / IS NOT NULL
cmp.IsNull(user.Email)
cmp.IsNotNull(user.Email)// IN查询
cmp.In(user.Status, new int[] { 1, 2, 3 })// BETWEEN
cmp.Between(user.Age, 18, 60)

5.3.3 逻辑运算符

// AND条件(使用 &)
cmp.Property(user.Status) == 1 & cmp.Property(user.Age) >= 18// OR条件(使用 |)
cmp.Property(user.Status) == 1 | cmp.Property(user.Status) == 2// 复杂条件组合
(cmp.Property(user.Status) == 1 | cmp.Property(user.Status) == 2) 
& cmp.Property(user.Age) >= 18// 嵌套条件
var oql = OQL.From(user).Select().Where(cmp => cmp.Property(user.Name) == "张三" | (cmp.Property(user.Age) >= 18 & cmp.Property(user.Status) == 1)).END;
// WHERE Name='张三' OR (Age>=18 AND Status=1)

5.3.4 Comparer方法详解

// Comparer方法签名
cmp.Comparer(object propertyValue, string compareSymbol, object value)// 使用示例
cmp.Comparer(user.Name, "=", "张三")
cmp.Comparer(user.Age, ">", 18)
cmp.Comparer(user.Name, "like", "张%")
cmp.Comparer(user.Status, "in", new int[]{1,2,3})
cmp.Comparer(user.Email, "is", null)
cmp.Comparer(user.Email, "is not", null)

5.3.5 动态条件构建

public List<UserEntity> SearchUsers(string name, int? status, int? minAge)
{UserEntity user = new UserEntity();var oql = OQL.From(user).Select().Where(cmp =>{// 动态构建条件OQLCompare condition = cmp.Property(user.ID) > 0;  // 默认条件if (!string.IsNullOrEmpty(name)){condition = condition & cmp.Comparer(user.Name, "like", $"%{name}%");}if (status.HasValue){condition = condition & cmp.Property(user.Status) == status.Value;}if (minAge.HasValue){condition = condition & cmp.Property(user.Age) >= minAge.Value;}return condition;}).OrderBy(user.ID).END;return EntityQuery<UserEntity>.QueryList(oql);
}

5.4 分页查询

5.4.1 Limit方法

UserEntity user = new UserEntity();var oql = OQL.From(user).Select().OrderBy(user.ID)  // 分页通常需要排序.END;// 基本分页:Limit(每页记录数, 页码)
oql.Limit(10, 1);  // 第1页,每页10条
oql.Limit(10, 2);  // 第2页,每页10条var users = EntityQuery<UserEntity>.QueryList(oql);

5.4.2 获取总记录数

var oql = OQL.From(user).Select().Where(cmp => cmp.Property(user.Status) == 1).OrderBy(user.ID).END;// 第三个参数为true,表示同时计算总记录数
oql.Limit(10, 1, true);var users = EntityQuery<UserEntity>.QueryList(oql);// 获取总记录数
int totalCount = oql.PageWithAllRecordCount;

5.4.3 传入已知总数

// 首次查询获取总数
var oql = OQL.From(user).Select().OrderBy(user.ID).END;
oql.Limit(10, 1, true);
var users1 = EntityQuery<UserEntity>.QueryList(oql);
int totalCount = oql.PageWithAllRecordCount;// 后续查询传入已知总数,提高性能
var oql2 = OQL.From(user).Select().OrderBy(user.ID).END;
oql2.Limit(10, 2, totalCount);  // 第2页,传入已知总数
var users2 = EntityQuery<UserEntity>.QueryList(oql2);

5.4.4 Top N查询

var oql = OQL.From(user).Select().OrderBy(o => o.Desc(user.CreateTime)).END;oql.TopCount = 10;  // 只取前10条var topUsers = EntityQuery<UserEntity>.QueryList(oql);

5.5 关联查询

5.5.1 InnerJoin

OrderEntity order = new OrderEntity();
UserEntity user = new UserEntity();var oql = OQL.From(order).InnerJoin(user).On(order.UserId, user.ID).Select().Where(cmp => cmp.Property(order.Status) == 1).END;// 使用EntityContainer映射结果
EntityContainer ec = new EntityContainer(oql);
var list = ec.MapToList(() => new {OrderId = order.ID,OrderNo = order.OrderNo,UserName = user.Name
});

5.5.2 LeftJoin

OrderEntity order = new OrderEntity();
UserEntity user = new UserEntity();var oql = OQL.From(order).LeftJoin(user).On(order.UserId, user.ID).Select().END;// 左连接时,user可能为null

5.5.3 多表关联

OrderEntity order = new OrderEntity();
UserEntity user = new UserEntity();
ProductEntity product = new ProductEntity();var oql = OQL.From(order).InnerJoin(user).On(order.UserId, user.ID).InnerJoin(product).On(order.ProductId, product.ID).Select().Where(cmp => cmp.Property(order.Status) == 1).OrderBy(o => o.Desc(order.CreateTime)).END;EntityContainer ec = new EntityContainer(oql);
var list = ec.MapToList(() => new OrderDetailDto {OrderId = order.ID,OrderNo = order.OrderNo,UserName = user.Name,ProductName = product.Name,Price = order.Price
});

5.5.4 子查询

// 查询有订单的用户
UserEntity user = new UserEntity();
OrderEntity order = new OrderEntity();var subOql = OQL.From(order).Select(order.UserId).Where(cmp => cmp.Property(order.Status) == 1).END;var oql = OQL.From(user).Select().Where(cmp => cmp.In(user.ID, subOql))  // IN子查询.END;

5.6 聚合查询

5.6.1 Count查询

UserEntity user = new UserEntity();var oql = OQL.From(user).Select(OQL.Count).Where(cmp => cmp.Property(user.Status) == 1).END;// 方式1:使用ExecuteScalar
AdoHelper db = MyDB.GetDBHelper();
int count = Convert.ToInt32(db.ExecuteScalar(oql.ToString(), oql.Parameters));// 方式2:使用EntityContainer
EntityContainer ec = new EntityContainer(oql);
var result = ec.MapToScalar<int>();

5.6.2 GroupBy分组

OrderEntity order = new OrderEntity();var oql = OQL.From(order).Select(order.Status, OQL.Count).GroupBy(order.Status).END;EntityContainer ec = new EntityContainer(oql);
var groups = ec.MapToList(() => new {Status = order.Status,Count = 0  // 将被实际值替换
});

5.6.3 Having子句

OrderEntity order = new OrderEntity();var oql = OQL.From(order).Select(order.UserId, OQL.Sum(order.Price)).GroupBy(order.UserId).Having(cmp => cmp.Comparer(OQL.Sum(order.Price), ">", 1000)).END;// SELECT UserId, SUM(Price) FROM Order GROUP BY UserId HAVING SUM(Price) > 1000

5.7 更新与删除

5.7.1 OQL批量更新

UserEntity user = new UserEntity();
user.Status = 0;  // 设置要更新的值var oql = OQL.From(user).Update(user.Status)  // 指定更新的字段.Where(cmp => cmp.Property(user.LastLoginTime) < DateTime.Now.AddDays(-30)).END;int affected = EntityQuery<UserEntity>.ExecuteOql(oql);
// UPDATE TbUser SET Status=0 WHERE LastLoginTime < '2024-01-01'

5.7.2 更新多个字段

UserEntity user = new UserEntity();
user.Status = 0;
user.UpdateTime = DateTime.Now;var oql = OQL.From(user).Update(user.Status, user.UpdateTime)  // 更新多个字段.Where(cmp => cmp.Property(user.ID) == 100).END;int affected = EntityQuery<UserEntity>.ExecuteOql(oql);

5.7.3 OQL删除

UserEntity user = new UserEntity();var oql = OQL.From(user).Delete().Where(cmp => cmp.Property(user.Status) == 0 & cmp.Property(user.CreateTime) < DateTime.Now.AddYears(-1)).END;int affected = EntityQuery<UserEntity>.ExecuteOql(oql);
// DELETE FROM TbUser WHERE Status=0 AND CreateTime < '2023-01-01'

5.8 GOQL泛型查询

5.8.1 GOQL基本用法

using PWMIS.Core.Extensions;// 无需创建实体对象
var users = OQL.FromObject<UserEntity>().Select().Where((cmp, u) => cmp.Property(u.Status) == 1).OrderBy((o, u) => o.Desc(u.ID)).Limit(10, 1).ToList();

5.8.2 GOQL与接口类型

// 使用接口类型查询
var users = OQL.FromObject<IUser>().Select().Where((cmp, u) => cmp.Property(u.Name) == "张三").ToList();// 指定表名
var users2 = OQL.FromObject<IUser>("CustomUserTable").Select().ToList();

5.8.3 GOQL链式调用

// 完整的链式调用
var result = OQL.FromObject<UserEntity>().Select(s => new object[] { s.ID, s.Name, s.Email }).Where((cmp, u) => cmp.Property(u.Status) == 1 & cmp.Comparer(u.Name, "like", "张%")).OrderBy((o, u) => o.Asc(u.Name)).Limit(20, 1, true).ToList();

5.9 OQL调试与优化

5.9.1 查看生成的SQL

var oql = OQL.From(user).Select().Where(user.Status).END;// 输出SQL语句
Console.WriteLine(oql.ToString());// 输出参数信息
Console.WriteLine(oql.PrintParameterInfo());

5.9.2 使用查询日志

// 开启查询日志
PWMIS.DataProvider.Data.CommandLog.Instance.Enabled = true;
PWMIS.DataProvider.Data.CommandLog.Instance.LogFile = "query.log";// 执行查询
var users = EntityQuery<UserEntity>.QueryList(oql);// 日志会记录所有执行的SQL和参数

5.9.3 性能优化建议

  1. 只查询需要的字段
// 推荐:只查询需要的字段
var oql = OQL.From(user).Select(user.ID, user.Name)  // 不要 Select() 全选.END;
  1. 合理使用分页
// 推荐:使用分页避免一次加载过多数据
oql.Limit(100, 1);
  1. 利用索引
// 确保WHERE条件中的字段有索引
var oql = OQL.From(user).Select().Where(user.ID)  // ID是主键,有索引.END;
  1. 避免在循环中查询
// 不推荐
foreach(var id in ids)
{var user = GetUser(id);  // N次查询
}// 推荐:批量查询
var oql = OQL.From(user).Select().Where(cmp => cmp.In(user.ID, ids)).END;
var users = EntityQuery<UserEntity>.QueryList(oql);

5.10 本章小结

本章详细介绍了OQL查询语言的各个方面:

  1. 基本语法:From、Select、Where、OrderBy、END
  2. 条件表达式:OQLCompare的使用,比较和逻辑运算符
  3. 分页查询:Limit方法,获取总记录数
  4. 关联查询:InnerJoin、LeftJoin、多表关联
  5. 聚合查询:Count、GroupBy、Having
  6. 更新删除:使用OQL进行批量更新和删除
  7. GOQL:泛型OQL的简化用法
  8. 调试优化:查看SQL、查询日志、性能优化

OQL是SOD框架的核心特性之一,熟练掌握OQL可以让你高效地进行各种数据查询操作。


下一章预告:第六章将深入讲解SQL-MAP技术,包括XML配置、参数化查询、DAL代码生成等内容。

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

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

相关文章

04-实体类与ORM映射

第四章:实体类与ORM映射 4.1 实体类基础 4.1.1 EntityBase类详解 EntityBase是SOD框架中所有实体类的基类,它提供了动态属性管理、元数据映射和状态追踪等核心功能。 public abstract class EntityBase {// ===== 核…

AI元人文:论数字猴戏与缺失的“破茧之悟”

AI元人文:论数字猴戏与缺失的“破茧之悟” 在方寸屏幕之间,一场亘古的“猴戏”正在全新上演。 数字班主取代了古道艺人,虚拟锣鼓替换了乡野铜钹,流量与点赞成了新的喝彩。这场戏码,从乡土戏台迁至算法剧场,围观与…

02-框架架构与核心组件

第二章:框架架构与核心组件 2.1 整体架构设计 2.1.1 分层架构 SOD框架采用经典的分层架构设计,从底层到顶层依次为: ┌────────────────────────────────────────────…

03-快速入门与环境配置

第三章:快速入门与环境配置 3.1 开发环境准备 3.1.1 必要的开发工具工具 要求 说明Visual Studio 2019/2022 推荐使用最新版本.NET SDK 2.0 - 8.0 根据项目目标框架选择NuGet 内置 包管理工具SQL Server / MySQL / 其…

01-框架概述与设计理念

第一章:SOD框架概述与设计理念 1.1 SOD框架简介 1.1.1 什么是SOD框架 SOD框架(SQL-MAP、ORM、Data Controls)是一个拥有超过15年历史的国产开源企业级数据应用开发框架。它诞生于2006年,最初名为PDF.NET框架,后来…

小红书代运营公司TOP5权威推荐:资质齐全品牌甄选,助力企业

当下,小红书以2.6亿月活用户、70%以上的年轻消费群体成为企业精准获客的核心阵地。2024年数据显示,小红书企业号数量同比增长65%,但超30%的企业因代运营选择不当遭遇流量陷阱:内容同质化导致笔记零曝光、投流ROI不…

电力电缆厂家TOP5权威推荐:甄选质量过硬、客户反馈佳的供应

电缆作为能源传输与工业运行的血管,其品质直接决定项目安全与长期价值。2024年数据显示,我国电缆市场规模超1.2万亿元,但58%的工程安全事故与劣质电缆相关,30%的采购方因选型不当导致返工损失。面对非标泛滥、适配…

CF1666C-Connect the Points

CF1666C-Connect the Points 题目大意 给你平面上的三个点,用垂直于坐标轴的线段连接这三个点,使得线段总长度最小。 题解 考虑 \(x\) 坐标中间的那个点,建立一条覆盖三个点纵坐标的竖直的线段。将两侧的两个点通过…

打磨细节质感,成就卓越代码——《代码大全2》第六部分读后感

打磨细节质感,成就卓越代码——《代码大全2》第六部分读后感 《代码大全2》第六部分“代码构建中的细节”聚焦编程实践的微观层面,从变量命名、注释风格、代码格式到控制结构优化、异常处理规范等细节入手,系统阐述…

哈尔滨精密轴承代理商综合实力TOP10排行榜

为了让榜单经得起推敲,我们联合黑龙江省机械工程学会,参照国际轴承协会(FAGMA)2025 年最新标准,花了两个月做实地调研。所有数据均经第三方机构 “中机检测” 验证,全程拒绝企业自报数据,这也是为啥能成为多家国…

2025年工业冷风机节能效率排行榜出炉,炼胶车间通风降温/制造业车间通风降温/机械厂车间降温/炼钢车间通风降温工业冷风机厂商选哪家

行业格局深度解析 随着制造业绿色转型加速,工业冷风机作为车间降温的关键设备,其节能效率成为企业采购的核心考量因素。据最新市场调研数据显示,2024年工业冷风机市场规模已达127亿元,同比增长18.3%。本文基于公开…

2025 年 11 月空调机组厂家最新推荐,实力品牌深度解析采购无忧之选!

2025 年全球商用空调机组市场需求持续攀升,规模预计突破 920 亿美元,同比增长 8.5%,但行业数据显示,42% 的采购方因品牌选择失误导致后期维护成本增加 30% 以上。为破解采购困境,本次推荐联合国际空气处理与制冷协…

3. vim上手 - 实践

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

深耕代码质量,筑牢工程根基——《代码大全2》第四部分读后感

深耕代码质量,筑牢工程根基——《代码大全2》第四部分读后感 《代码大全2》第四部分“全面质量管理”以“构建高质量代码”为核心,从软件质量的本质、缺陷预防、测试策略到持续改进,系统拆解了代码从“可用”到“优…

2025年哈尔滨精密轴承厂家综合实力前十强排行榜

轴承的 “灵魂” 是精度,我们以 P 级精度(P2/P4/P5)量产能力为核心指标,参考数字化车间建设水平。像新哈精密轴承有黑龙江省数字化示范车间,哈轴集团能实现 P4 级轴承工业化量产,这类企业直接加分。一、选轴承像…

2025年空调机组厂家最新推荐,产能、专利、环保三维数据透视!

2025 年全球空调机组市场规模持续扩容,据行业测算同比增长 7.5%,但产品性能参差、适配性不足等问题仍困扰采购决策。本次推荐基于国际权威测评标准编制,测评流程严格遵循 ANSI/ASHRAE Standard 16-2016 检测规范,对…

2025年空调机组厂家最新推荐,组合式,直膨式净化,变风量,远程射流,转轮热回收空调机组公司测评

2025 冷年全球空调总出货规模达 2.21 亿台,同比增长 12.9%,但市场中 TOP6-8 长尾品牌均价下滑 22% 仍难提升份额,产品性能与可靠性差异显著。为破解采购决策难题,本次推荐依托国际权威测评体系编制,测评流程严格遵…

2025年度工部优选十大品牌排名:工部优选的十个领先品牌是什

工程行业的品牌选择向来是甲方、施工单位与设计院的核心痛点——虚假榜单充斥市场、低价内卷扰乱判断、跨平台调研消耗大量时间。作为工程行业生态服务平台的标杆,工部优选依托业主、设计院、总包的真实采购数据,发布…

2025年十大诚信且资质齐全的宅基地建房企业推荐,专业乡墅设

在乡村振兴的浪潮下,越来越多的人选择返乡建房,一栋安全可靠、设计合理的宅基地自建房,成为承载乡愁与家庭幸福的重要载体。然而,乡村建房市场鱼龙混杂,如何找到诚信可靠、资质齐全的宅基地建房企业,成为许多人的…

如何被更新的?就是[人工智能-大模型-122]:模型层 - RNN是通过神经元还是通过张量时间记录状态信息?时间状态信息

如何被更新的?就是[人工智能-大模型-122]:模型层 - RNN是通过神经元还是通过张量时间记录状态信息?时间状态信息pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; …