TSQL用户指南
1. 基础
构造TSQL有两种方式,一种是通过我们的DSL,一种是通过字符串拼接方式
推荐使用DSL方式
1.1 使用TSQL DSL
使用TSQL-DSL的理由
-
易于维护,SQL维护简单,采用TSQL DSL拼装SQL,后期易于维护,相对于字符串拼接修改不易报错
-
安全,能有效防止SQL注入
-
规范,容易规范代码
-
高效,不需要单独传递SQL参数,TSQL DSL可以直接获取params,查询时直接走预编译模式。
-
灵活,TSQL DSL 会自动给字段拼接反引号,可以做一些动态SQL的拼接。
目前TSQL DSL只提供了基于模型的查询接口,后期有需求将继续提供create update接口,上面列举了一些简单的场景,使用中有其他场景不知道怎么使用TSQL DSL构造TSQL查询语句欢迎咨询DataStore。TSQL DSL主要是基于开源持久层框架JOOQ进行了简单的改造,基本用法和JOOQ保持一致。
1.2 DSL使用示例
1.2.1 简单示例
TSQL:想要的T-SQL查询语句
select id, siteName from WarehouseExtBO where id = 1;DSL:通过DSL构造TSQL查询语句,获取查询结果
Query query = TSQL.select(TSQL.field(WarehouseExtBO.id_field)) .select(TSQL.field(WarehouseExtBO.siteName_field)) .from(WarehouseExtBO.class) .where(TSQL.field(WarehouseExtBO.id_field).eq(1)); 或者Query query = TSQL.select(TSQL.field(WarehouseExtBO.id_field), TSQL.field(WarehouseExtBO.siteName_field)) .from(WarehouseExtBO.class) .where(TSQL.field(WarehouseExtBO.id_field).eq(1)); //查询: List<WarehouseExtBO> result = DS.findAll(query); ....TSQL:想要的T-SQL查询语句
select * from WarehouseExtBO;DSL:通过DSL构造TSQL查询语句
Query query = TSQL.selectFrom(WarehouseExtBO.class); 或者Query query = TSQL.select().from(WarehouseExtBO.class);TSQL:想要的T-SQL查询语句
select id, siteName from WarehouseExtBO where id = 1 order by createdAt;DSL:通过DSL构造TSQL查询语句,获取查询结果
Query query = TSQL.select(TSQL.field(WarehouseExtBO.id_field)) .select(TSQL.field(WarehouseExtBO.siteName_field)) .from(WarehouseExtBO.class) .where(TSQL.field(WarehouseExtBO.id_field).eq(1)) .orderBy(TSQL.field(WarehouseExtBO.createdAt_field)); //查询: List<WarehouseExtBO> result = DS.findAll(query); ....TSQL:想要的T-SQL查询语句
select id, siteName from WarehouseExtBO where id = 1 order by createdAt desc;DSL:通过DSL构造TSQL查询语句,获取查询结果
Query query = TSQL.select(TSQL.field(WarehouseExtBO.id_field)) .select(TSQL.field(WarehouseExtBO.siteName_field)) .from(WarehouseExtBO.class) .where(TSQL.field(WarehouseExtBO.id_field).eq(1)) .orderBy(TSQL.field(WarehouseExtBO.createdAt_field).desc()); //查询: List<WarehouseExtBO> result = DS.findAll(query); ....TSQL:想要的T-SQL查询语句
select id, siteName from WarehouseExtBO where id = 1 group by createdAt;DSL:通过DSL构造TSQL查询语句,获取查询结果
Query query = TSQL.select(TSQL.field(WarehouseExtBO.id_field)) .select(TSQL.field(WarehouseExtBO.siteName_field)) .from(WarehouseExtBO.class) .where(TSQL.field(WarehouseExtBO.id_field).eq(1)) .groupBy(TSQL.field(WarehouseExtBO.createdAt_field)); //查询: List<WarehouseExtBO> result = DS.findAll(query); ....TSQL:想要的T-SQL查询语句
select count(1) from WarehouseExtBO;DSL:通过DSL构造TSQL查询语句,获取查询结果
Query query = TSQL.selectCount().from(WarehouseExtBO.class); //查询: IntResult result = DS.count(query); ....1.2.2 包含Link相关字段的关联查询
TSQL:想要的T-SQL查询语句
select `*`, `parentSite`.`*`, `person`.`personName`from md_SiteBOwhere `person`.`personName` = '张三';DSL:通过DSL构造TSQL查询语句
Query query = TSQL.select(TSQL.field("*")) .select(TSQL.field(WarehouseExtBO.parentSite_field, "*")) .select(TSQL.field(WarehouseExtBO.person_field, PersonBO.personName_field)) .from(WarehouseExtBO.class) .where(TSQL.field(WarehouseExtBO.person_field, PersonBO.personName_field) .eq("张三"));TSQL:想要的T-SQL查询语句
select id from WarehouseExtBO where companyEntity.entityName = 'entityName' and channel.channelName = 'channelName';DSL:通过DSL构造TSQL查询语句
Query query = TSQL.select(TSQL.field(WarehouseExtBO.id_field)) .from(WarehouseExtBO.class) .where(TSQL.field(WarehouseExtBO.companyEntity_field, EntityBO.entityName_field) .eq("entityName")) .and(TSQL.field(WarehouseExtBO.channel_field, ChannelBO.channelName_field) .eq("channelName"));2. 示例
场景一: 两级关联模型查询
模型定义
- OrderBO
@Model(name = "Order")public class OrderBO extends BaseModel {
//************** 存储字段 *************
@TextMeta(length = 64) @Field(name = "Order title") private String orderTitle;
//************** 计算字段 *************
@LookupMeta @Field(name = "Order line list") private List<OrderLineBO> orderLineList;
}- OrderLineBO
@Model(name = "Order line")public class OrderLineBO extends BaseModel {
//************** 存储字段 *************
@LinkMeta @Field(name = "Order") private OrderBO order;
@TextMeta(length = 64) @Field(name = "Order title") private String orderLineTitle;}API使用
创建: 创建主模型 + 子模型
- DS API写法
// 下面这段逻辑适用于FuncLong orderId = DS.nextId(OrderBO.class);orderToCreate.setOrderId(orderId);
for (OrderLineBO orderLineToCreate : orderLineListToCreate) { Long orderLineId = DS.nextId(OrderLineBO.class); orderLineToCreate.setId(orderLineId); orderLineToCreate.setOrder(orderToCreate);}
// 持久化主模型DS.create(orderToCreate);
// 持久化子模型DS.create(orderLineListToCreate);-
生成的T-SQL
-
实际执行的SQL
-
JSON 格式结果集
更新: 更新主子模型 + 子模型
- DS API写法
// 持久化主模型DS.update(orderToUpdate);
if (orderToUpdate.getOrderLineList() == null || orderToUpdate.getOrderLineList().isEmpty()) { throw new BusinessException("Order.orderLineListCantBeEmpty")}
// 持久化子模型DS.update(orderToUpdate.getOrderLineList());-
生成的T-SQL
-
实际执行的SQL
-
JSON 格式结果集
对象查询: 通过主模型ID查询主模型,会自动带出当前Link和LinkMany模型的id,不会自动带出Lookup类型的模型id
- DS API写法
OrderBO resultOrder = DS.findById(OrderBO.class, id);- 生成的T-SQL
SELECT * FROM `trade_OrderBO` WHERE `id` = '<id>';- 实际执行的SQL
SELECT `id`, `orderTitle`, `updatedAt`, `createdAt`, `isDeleted`, `deletedAt`, `UpdatedBy` AS `updatedBy`, `CreatedBy` AS `createdBy`FROM `trade__order_b_o`WHERE (`id` = '1') AND `isDeleted` = 0;- JSON 格式结果集
{ "requestId": "0jt6q9qno3", "err": null, "res": { "selectResult": [ { "id": 1, "orderTitle": "order1", "updatedAt": 1614568392000, "createdAt": 1614568392000, "isDeleted": false, "deletedAt": 0, "updatedBy": null, "createdBy": null } ] }, "success": true}对象查询: 通过主模型ID查询主子模型数据
- DS API写法
OrderBO resultOrder = DS.findOne(OrderBO.class, "*, `orderLineList`.*", "`id` = ?", order.getId());- TSQL-DSL写法
Query query = TSQL.select(TSQL.field("*")) .select(TSQL.field(OrderBO.orderLineList_field, "*")) .from(OrderBO.class) .where(TSQL.field(OrderBO.id_field).eq(order.getId()));
OrderBO result = DS.findOne(query);- 生成的T-SQL
SELECT *, `orderLineList`.* FROM `trade_OrderBO` WHERE `id` = '<id>';- 实际执行的SQL
--查询主模型SELECT `id`, `orderTitle`, `updatedAt`, `createdAt`, `isDeleted`, `deletedAt`, `UpdatedBy` AS `updatedBy`, `CreatedBy` AS `createdBy`FROM `trade__order_b_o`WHERE (`id` = '1') AND `isDeleted` = 0;
--根据主模型id查询子模型(orderLineList为主模型上的lookup字段,关联字段在主表上)SELECT `order` AS `order`, `id`, `orderLineTitle`, `updatedAt`, `createdAt`, `isDeleted`, `deletedAt`, `UpdatedBy` AS `updatedBy`, `CreatedBy` AS `createdBy`, `order` AS `order`FROM `trade__order_line_b_o`WHERE (`order` IN (1)) AND `isDeleted` = 0;- JSON 格式结果集
{ "requestId": "ayxvkmsaac", "err": null, "res": { "selectResult": [ { "id": 1, "orderTitle": "order1", "updatedAt": 1614568392000, "createdAt": 1614568392000, "isDeleted": false, "deletedAt": 0, "updatedBy": null, "createdBy": null, "orderLineList": [ { "order": { "id": 1 }, "id": 1, "orderLineTitle": "orderLineTitle1", "updatedAt": 1614568392000, "createdAt": 1614568392000, "isDeleted": false, "deletedAt": 0, "updatedBy": null, "createdBy": null } ] } ] }, "success": true}对象查询: 通过子模型ID反查主子模型
- DS API写法
OrderLineBO resultOrderLine = DS.findOne(OrderLineBO.class, "*, order.*", "id = ?", orderLine.getId());- TSQL-DSL写法
Query query = TSQL.select(TSQL.field("*")) .select(TSQL.field(OrderLineBO.order_field, "*")) .from(OrderLineBO.class) .where(TSQL.field(OrderLineBO.id_field).eq(orderLine.getId()));
OrderLineBO result = DS.findOne(query);- 生成的T-SQL
SELECT *, `order`.* FROM `trade_OrderLineBO` WHERE `id` = '<id>';- 实际执行的SQL
--查询trade_OrderLineBO模型,同时查询link字段orderSELECT `id`, `orderLineTitle`, `updatedAt`, `createdAt`, `isDeleted`, `deletedAt`, `UpdatedBy` AS `updatedBy`, `CreatedBy` AS `createdBy`, `order` AS `order`FROM `trade__order_line_b_o`WHERE (`id` = '1') AND `isDeleted` = 0;
--根据上一步查到的order id查询OrderBO模型表SELECT `id`, `orderTitle`, `updatedAt`, `createdAt`, `isDeleted`, `deletedAt`, `UpdatedBy` AS `updatedBy`, `CreatedBy` AS `createdBy`FROM `trade__order_b_o`WHERE (`id` IN (1)) AND `isDeleted` = 0;- JSON 格式结果集
{ "requestId": "500d1b8lq2", "err": null, "res": { "selectResult": [ { "id": 1, "orderLineTitle": "orderLineTitle1", "updatedAt": 1614568392000, "createdAt": 1614568392000, "isDeleted": false, "deletedAt": 0, "updatedBy": null, "createdBy": null, "order": { "id": 1, "orderTitle": "order1", "updatedAt": 1614568392000, "createdAt": 1614568392000, "isDeleted": false, "deletedAt": 0, "updatedBy": null, "createdBy": null } } ] }, "success": true}列表查询: 通过主模型条件查询主子模型
- DS API写法
List<OrderBO> resultOrderList = DS.findAll(OrderBO.class, "*, `orderLineList`.*", "`orderTitle` like ?", order.getOrderTitle() + "%");- TSQL-DSL写法
TSQL.select(TSQL.field("*")) .select(TSQL.field(OrderBO.orderLineList_field, "*")) .from(OrderBO.class) .where(TSQL.field(OrderBO.orderTitle_field).startsWith(order.getOrderTitle()));List<OrderBO> orderBOList = DS.findAll(query);- 生成的T-SQL
SELECT *, `orderLineList`.* FROM `trade_OrderBO` WHERE `orderTitle` like 'order%';- 实际执行的SQL
SELECT `id`, `orderTitle`, `updatedAt`, `createdAt`, `isDeleted`, `deletedAt`, `UpdatedBy` AS `updatedBy`, `CreatedBy` AS `createdBy`FROM `trade__order_b_o`WHERE (`orderTitle` LIKE 'order%') AND `isDeleted` = 0;- JSON 格式结果集
{ "requestId": "2tgrmo38c0", "err": null, "res": { "selectResult": [ { "id": 1, "orderTitle": "order1", "updatedAt": 1614568392000, "createdAt": 1614568392000, "isDeleted": false, "deletedAt": 0, "updatedBy": null, "createdBy": null, "orderLineList": [ { "order": { "id": 1 }, "id": 1, "orderLineTitle": "orderLineTitle1", "updatedAt": 1614568392000, "createdAt": 1614568392000, "isDeleted": false, "deletedAt": 0, "updatedBy": null, "createdBy": null } ] } ] }, "success": true}列表查询: 通过主子模型的条件查询主子模型
- DS API写法
List<OrderBO> resultOrderList = DS .findAll( OrderBO.class, "*, orderLineList.*", "orderTitle like ? and orderLineList.orderLineTitle like ?", order.getOrderTitle() + "%", "%Title" );- TSQL-DSL
Query query = TSQL.select(TSQL.field("*")) .select(TSQL.field(OrderBO.orderLineList_field, "*")) .from(OrderBO.class) .where(TSQL.field(OrderBO.orderTitle_field).startsWith(order.getOrderTitle() + "%")) .and(TSQL.field(OrderBO.orderLineList_field, OrderLineBO.orderLineTitle_field).endsWith("Title"));
List<OrderBO> orderBOList = DS.findAll(query);- 生成的T-SQL
SELECT *, `orderLineList`.* FROM `trade_OrderBO`WHERE `orderTitle` LIKE 'order%'AND `orderLineList`.`orderLineTitle` LIKE '%Title';- 实际执行的SQL
SELECT `id`, `orderTitle`, `updatedAt`, `createdAt`, `isDeleted`, `deletedAt`, `UpdatedBy` AS `updatedBy`, `CreatedBy` AS `createdBy`FROM `trade__order_b_o`WHERE ( `orderTitle` LIKE 'order%' AND `id` IN ( SELECT `order` FROM `trade__order_line_b_o` WHERE `orderLineTitle` LIKE '%Title' ) ) AND `isDeleted` = 0;列表查询: 通过is null条件查询主子模型
- DS API写法
List<OrderBO> resultOrderList = DS .findAll( OrderBO.class, "*, orderLineList.*", "orderTitle is null and orderLineList.orderLineTitle is null" );- TSQL-DSL写法
Query query = TSQL.select(TSQL.field("*")) .select(TSQL.field(OrderBO.orderLineList_field, "*")) .from(OrderBO.class) .where(TSQL.field(OrderBO.orderTitle_field).isNull()) .and(TSQL.field(OrderBO.orderLineList_field, OrderLineBO.orderLineTitle_field).isNull());
List<OrderBO> orderBOList2 = DS.findAll(query);- 生成的T-SQL
SELECT *, `orderLineList`.* FROM `trade_OrderBO`WHERE `orderTitle` is nullAND `orderLineList`.`orderLineTitle` is null ;- 实际执行的SQL
SELECT `id`, `orderTitle`, `updatedAt`, `createdAt`, `isDeleted`, `deletedAt`, `UpdatedBy` AS `updatedBy`, `CreatedBy` AS `createdBy`FROM `trade__order_b_o`WHERE ( `orderTitle` IS NULL AND `id` IN ( SELECT `order` FROM `trade__order_line_b_o` WHERE `orderLineTitle` IS NULL ) ) AND `isDeleted` = 0;分页查询: 通过主模型条件查询主子模型
- DS API写法
Paging<OrderBO> paging = DS.paging(OrderBO.class, "*, orderLineList.*", "orderTitle like ?", new Page(1, 20), "%" + order.getOrderTitle());- TSQL-DSL写法
//获取分页数据Page page = new Page(1, 20);Query query = TSQL.select(TSQL.field("*")) .select(TSQL.field(OrderBO.orderLineList_field, "*")) .from(OrderBO.class) .where(TSQL.field(OrderBO.orderTitle_field).endsWith(order.getOrderTitle())) .limit(page.first(), page.limit());List<OrderBO> result = DS.findAll(query);Paging<OrderBO> paging = new Paging<>();paging.setData(result);
//是否需要查询分页总数量if (!page.isSkipCount()) { Query queryTotal = TSQL.selectCount() .from(OrderBO.class) .where(TSQL.field(OrderBO.orderTitle_field).endsWith(order.getOrderTitle())); long total = DS.count(queryTotal); paging.setTotal(total);}return paging;- 生成的T-SQL
SELECT count(*) FROM `trade_OrderBO` WHERE `orderTitle` like '%order';SELECT *, orderLineList.* FROM `trade_OrderBO` WHERE `orderTitle` like '%order' LIMIT 0,20;- 实际执行的SQL
SELECT COUNT(*) FROM `trade__order_b_o` WHERE ( `orderTitle` LIKE '%order' ) AND `isDeleted` = 0 ;
SELECT `id`, `orderTitle`, `updatedAt`, `createdAt`, `isDeleted`, `deletedAt`, `UpdatedBy` AS `updatedBy`, `CreatedBy` AS `createdBy`FROM `trade__order_b_o`WHERE (`orderTitle` LIKE 'order%') AND `isDeleted` = 0LIMIT 0, 20;
SELECT `order` AS `order`, `id`, `orderLineTitle`, `updatedAt`, `createdAt`, `isDeleted`, `deletedAt`, `UpdatedBy` AS `updatedBy`, `CreatedBy` AS `createdBy`, `order` AS `order`FROM `trade__order_line_b_o`WHERE (`order` IN (1)) AND `isDeleted` = 0;场景二: 多层嵌套查询
图示

模型定义
- ContractBO
@Model(name = "Contract")public class ContractBO extends BaseModel {
//************** 存储字段 *************
@TextMeta(length = 64) @Field(name = "Order title") private String contractTitle;
//************** 计算字段 *************
@LookupMeta @Field(name = "Order list") private List<OrderBO> orderList;
@LookupMeta @Field(name = "Order line list") private List<OrderLineBO> orderLineList;
}- OrderBO
@Model(name = "Order")public class OrderBO extends BaseModel {
//************** 存储字段 *************
@LinkMeta @Field(name = "Contract") private ContractBO contract;
@TextMeta(length = 64) @Field(name = "Order title") private String orderTitle;
//************** 计算字段 *************
@LookupMeta @Field(name = "Order line list") private List<OrderLineBO> orderLineList;
}- OrderLineBO
@Model(name = "Order line")public class OrderLineBO extends BaseModel {
//************** 存储字段 *************
@LinkMeta @Field(name = "Contract") private ContractBO contract;
@LinkMeta @Field(name = "Order") private OrderBO order;
@TextMeta(length = 64) @Field(name = "Order title") private String orderLineTitle;}API使用
对象查询: 通过主模型ID查询多层主子模型
- DS API写法
ContractBO resultContract = DS.findOne(ContractBO.class, "*, `orderList`.*, `orderLineList`.*", "`id` = ?", contract.getId());- TSQL-DSL写法
Query query = TSQL.select(TSQL.field("*")) .select(TSQL.field(ContractBO.orderList_field, "*")) .select(TSQL.field(ContractBO.orderLineList_field, "*")) .from(ContractBO.class) .where(TSQL.field(ContractBO.id_field).eq(contractBO.getId()));
ContractBO resultContract = DS.findOne(query);- 生成的T-SQL
SELECT *, `orderList`.*, `orderLineList`.* FROM `trade_ContractBO` WHERE `id` = '1'- 实际执行的SQL
--查询trade_ContractBO模型表SELECT `id` , `contractTitle` , `updatedAt` , `createdAt` , `isDeleted` , `deletedAt` , `UpdatedBy` AS `updatedBy` , `CreatedBy` AS `createdBy`FROM `trade__contract_b_o`WHERE ( `id` = '1' ) AND `isDeleted` = 0 ;--查询orderList关联的模型表SELECT `contract` AS `contract` , `id` , `orderLineTitle` , `updatedAt` , `createdAt` , `isDeleted` , `deletedAt` , `UpdatedBy` AS `updatedBy` , `CreatedBy` AS `createdBy` , `order` AS `order` , `contract` AS `contract`FROM `trade__order_b_o`WHERE ( `contract` IN (1 ) ) AND `isDeleted` = 0 ;--查询orderLineList关联的模型表SELECT `contract` AS `contract` , `id` , `orderTitle` , `updatedAt` , `createdAt` , `isDeleted` , `deletedAt` , `UpdatedBy` AS `updatedBy` , `CreatedBy` AS `createdBy` , `contract` AS `contract`FROM `trade__order_line_b_o`WHERE ( `contract` IN (1 ) ) AND `isDeleted` = 0 ;对象查询: 通过子模型ID反查多层主子模型
- DS API写法
OrderLineBO resultOrderLineBO = DS.findOne(OrderLineBO.class, "*, order.*, contract.*", "id = ?", orderLine.getId());- TSQL-DSL 写法
Query query = TSQL.select(TSQL.field("*")) .select(TSQL.field(OrderLineBO.order_field, "*")) .select(TSQL.field(OrderLineBO.contract_field, "*")) .from(OrderLineBO.class) .where(TSQL.field(OrderLineBO.id_field).eq(orderLineBO.getId()));
OrderLineBO result = DS.findOne(query);- 生成的T-SQL
SELECT *, `order`.*, `contract`.* FROM `trade_OrderLineBO` WHERE `id` = '1';- 实际执行的SQL
--查询子模型数据,同时查出order,contract关联的模型idSELECT `id` , `orderLineTitle` , `updatedAt` , `createdAt` , `isDeleted` , `deletedAt` , `UpdatedBy` AS `updatedBy` , `CreatedBy` AS `createdBy`FROM `trade__order_line_b_o`WHERE ( `id` = '1' ) AND `isDeleted` = 0 ;
--根据第一步查询出的contract id查询trade_ContractBO模型表SELECT `id` , `contractTitle` , `updatedAt` , `createdAt` , `isDeleted` , `deletedAt` , `UpdatedBy` AS `updatedBy` , `CreatedBy` AS `createdBy`FROM `trade__contract_b_o`WHERE ( `id` IN (1 ) ) AND `isDeleted` = 0 ;
--根据第一步查询出的order id查询trade_OrderBO模型关联表SELECT `id` , `orderTitle` , `updatedAt` , `createdAt` , `isDeleted` , `deletedAt` , `UpdatedBy` AS `updatedBy` , `CreatedBy` AS `createdBy` , `contract` AS `contract`FROM `trade__order_b_o`WHERE ( `id` IN (1 ) ) AND `isDeleted` = 0 ;列表查询: 通过主模型条件查询多层主子模型
- DS API写法
List<OrderBO> paging = DS.findAll(ContractBO.class, "*, orderList.*, orderLineList.*", "contractTitle like ?", contractBO.getContractTitle() + "%");- TSQL-DSL写法
Query query = TSQL.select(TSQL.field("*")) .select(TSQL.field(ContractBO.orderList_field, "*")) .select(TSQL.field(ContractBO.orderLineList_field, "*")) .from(ContractBO.class) .where(TSQL.field(ContractBO.contractTitle_field) .startsWith(contractBO.getContractTitle()));
ContractBO resultContract = DS.findAll(query);- 生成的T-SQL
SELECT *, `orderList`.*, `orderLineList`.*FROM `trade_ContractBO`WHERE contractTitle like 'contractTitle%';- 实际执行的SQL
--根据条件查询主模型数据,SELECT `id` , `contractTitle` , `updatedAt` , `createdAt` , `isDeleted` , `deletedAt` , `UpdatedBy` AS `updatedBy` , `CreatedBy` AS `createdBy`FROM `trade__contract_b_o`WHERE ( `contractTitle` LIKE 'contractTitle%' ) AND `isDeleted` = 0 ;--根据trade_ContractBO模型id过滤查询trade_OrderLineBO模型表SELECT `contract` AS `contract` , `id` , `orderLineTitle` , `updatedAt` , `createdAt` , `isDeleted` , `deletedAt` , `UpdatedBy` AS `updatedBy` , `CreatedBy` AS `createdBy` , `order` AS `order` , `contract` AS `contract`FROM `trade__order_line_b_o`WHERE ( `contract` IN (1 ) ) AND `isDeleted` = 0 ;--根据trade_ContractBO模型id过滤查询trade_OrderBO模型表SELECT `contract` AS `contract` , `id` , `orderTitle` , `updatedAt` , `createdAt` , `isDeleted` , `deletedAt` , `UpdatedBy` AS `updatedBy` , `CreatedBy` AS `createdBy` , `contract` AS `contract`FROM `trade__order_b_o`WHERE ( `contract` IN (1 ) ) AND `isDeleted` = 0 ;分页查询: 通过主模型条件查询多层主子模型
- DS API写法
Paging<ContractBO> resultContractPaging = DS .paging( ContractBO.class, "*, orderList.*, orderLineList.*", "id = ?", new Page(1, 20), contract.getId() );- TSQL-DSL
//获取分页数据Page page = new Page(1, 20);Query query = TSQL.select(TSQL.field("*")) .select(TSQL.field(ContractBO.orderList_field, "*")) .select(TSQL.field(ContractBO.orderLineList_field, "*")) .from(ContractBO.class) .where(TSQL.field(ContractBO.id_field).eq(contract.getId())) .limit(page.first(), page.limit());List<ContractBO> result = DS.findAll(query);Paging<OrderBO> paging = new Paging<>();paging.setData(result);
//是否需要查询分页总数量if (!page.isSkipCount()) { Query queryTotal = TSQL.selectCount() .from(ContractBO.class) .where(TSQL.field(ContractBO.id_field).eq(contract.getId())) long total = DS.count(queryTotal); paging.setTotal(total);}return paging;- 生成的T-SQL
SELECT count(*) FROM `trade_ContractBO` WHERE id = '1';SELECT *, `orderList`.*, `orderLineList`.* FROM `trade_ContractBO` WHERE id = '1' LIMIT 0,20;- 实际执行的SQL
SELECT COUNT(*) FROM `trade__contract_b_o` WHERE ( `id` = '1' ) AND `isDeleted` = 0 ;
SELECT `id` , `contractTitle` , `updatedAt` , `createdAtFROM `trade__contract_b_o`WHERE ( `id` = '1' ) AND `isDeleted` = 0 LIMIT 0 , 20 ;--根据trade_ContractBO模型id过滤查询trade_OrderLineBO模型表SELECT `contract` AS `contract` , `id` , `orderLineTitle` , `updatedAt` , `createdAt` , `isDeleted` , `deletedAt` , `UpdatedBy` AS `updatedBy` , `CreatedBy` AS `createdBy` , `order` AS `order` , `contract` AS `contract`FROM `trade__order_line_b_o`WHERE ( `contract` IN (1 ) ) AND `isDeleted` = 0 ;--根据trade_ContractBO模型id过滤查询trade_OrderBO模型表SELECT `contract` AS `contract` , `id` , `orderTitle` , `updatedAt` , `createdAt` , `isDeleted` , `deletedAt` , `UpdatedBy` AS `updatedBy` , `CreatedBy` AS `createdBy` , `contract` AS `contract`FROM `trade__order_b_o`WHERE ( `contract` IN (1 ) ) AND `isDeleted` = 0 ;场景三: 单模型
模型定义
- OrderBO
@Model(name = "Order")public class OrderBO extends BaseModel {
//************** 存储字段 *************
@TextMeta(length = 64) @Field(name = "Order title") private String orderTitle;
@Field(name = "count") private int count;
@Field(name = "tax amount") private Currency taxAmt;
@DateTimeMeta(unit = TimeUnit.SECONDS) @Field(name = "Ordered Time") private Date orderedTime;}API使用
创建: 创建单模型数据
- DS API写法
// 下面这段逻辑适用于FuncLong orderId = DS.nextId(OrderBO.class);orderToCreate.setId(orderId);IntResult result = DS.create(orderToCreate);- 生成的T-SQL
insert into `trade_OrderBo` (`id`, `orderTitle`, `count`, `orderedTime`, `createdBy`)values (1, 'this is title', 1000, 1533312000000, 1)- 实际执行的SQL
INSERT INTO `trade__order_b_o` (`id`, `orderTitle`, `count`, `orderedTime`, `createdBy`,`isDeleted`, `createdAt` , `updatedAt`)VALUES (1, 'this is title', 1000, 1533312000000, 1, 0, '2021-03-02 11:58:47' , '2021-03-02 11:58:47')- JSON 格式结果集
{ "requestId": "ey1yii3m4m", "err": null, "res": { "insertesult": [ 1 ] }, "success": true}创建: 批量创建单模型数据
- DS API写法
// 下面这段逻辑适用于Funcfor (OrderBO orderToCreate: orderListToCreate){ Long orderId = DS.nextId(OrderBO.class); orderToCreate.setOrderId(orderId);}
IntResult result = DS.create(orderListToCreate);- 生成的T-SQL
insert into `trade_OrderBo` (`id`, `orderTitle`, `count`, `orderedTime`, `createdBy`)values (1, 'this is title', 1000, 1533312000000, 1),(2, 'this is title', 1000, 1533312000000, 1),(3, 'this is title', 1000, 1533312000000, 1)- 实际执行的SQL
INSERT INTO `trade__order_b_o` (`id`, `orderTitle`, `count`, `orderedTime`, `createdBy`,`isDeleted`, `createdAt` , `updatedAt`)VALUES (1, 'this is title', 1000, 1533312000000, 1, 0, '2021-03-02 11:58:47' , '2021-03-02 11:58:47'),(2, 'this is title', 1000, 1533312000000, 1, 0, '2021-03-02 11:58:47' , '2021-03-02 11:58:47'),(3, 'this is title', 1000, 1533312000000, 1, 0, '2021-03-02 11:58:47' , '2021-03-02 11:58:47')- JSON 格式结果集
{ "requestId": "ey1yii3m4m", "err": null, "res": { "insertResult": [ 1,2,3 ] }, "success": true}更新: 更新单模型数据
- DS API写法
// 下面这段逻辑适用于FuncBooleanResult result = DS.update(orderToUpdate);// 下面这段逻辑适用于Flowfinal BooleanResult result = DS.update(orderToUpdate);- 生成的T-SQL
update `trade_OrderBo`set `orderTitle` = 'this is title',`count` = 2000,`updatedBy` = 1where `id` = 1;- 实际执行的SQL
UPDATE `trade__order_b_o`SET `orderTitle` = 'this is title',`count` = 2000,`updatedBy` = 1,`updatedAt`= '2021-03-02 11:58:47'WHERE ( `id` = 1 ) AND `isDeleted` = 0 ;- JSON 格式结果集
{ "requestId": "uqpnvpd1tz", "err": null, "res": { "updateResult": { "count": 1 } }, "success": true}更新: 根据条件更新单模型数据
- DS API写法
// 下面这段逻辑适用于FuncIntResult result = DS.update(OrderBO.class, "set `count` = `count` + 1", "`id` = 1");- DS DSL写法
Query update = TSQL.update(OrderBO.class) .set(TSQL.field(OrderBO.count_field), (Object) TSQL.field(OrderBO.count_field).add(1)) .where(TSQL.field(OrderBO.id_field).eq(1));IntResult result = DS.update(update);- 生成的T-SQL
UPDATE `trade_OrderBO` SET `count` = `count` + 1 WHERE `id` = 1;- 实际执行的SQL
UPDATE `trade__order_b_o` SET `count` = `count` + 1 WHERE ( `id` = 1 ) AND `isDeleted` = 0 ;更新: 批量更新单模型数据
- DS API写法
// 下面这段逻辑适用于FuncIntResult result = DS.update(orderListToUpdate);// 下面这段逻辑适用于Flowfinal IntResult result = DS.update(orderToUpdate);- 生成的T-SQL
update `trade_OrderBo` set `orderTitle` = 'this is title',`count` = 2000,`updatedBy` = 1 where `id` = 1;update `trade_OrderBo` set `orderTitle` = 'this is title',`count` = 3000,`updatedBy` = 1 where `id` = 2;update `trade_OrderBo` set `orderTitle` = 'this is title',`count` = 4000,`updatedBy` = 1 where `id` = 3;- 实际执行的SQL
UPDATE `trade__order_b_o` SET `orderTitle` = 'this is title',`count` = 2000,`updatedBy` = 1,`updatedAt`= '2021-03-02 11:58:47' WHERE ( `id` = 1 ) AND `isDeleted` = 0 ;UPDATE `trade__order_b_o` SET `orderTitle` = 'this is title',`count` = 3000,`updatedBy` = 1,`updatedAt`= '2021-03-02 11:58:47' WHERE ( `id` = 2 ) AND `isDeleted` = 0 ;UPDATE `trade__order_b_o` SET `orderTitle` = 'this is title',`count` = 4000,`updatedBy` = 1,`updatedAt`= '2021-03-02 11:58:47' WHERE ( `id` = 3 ) AND `isDeleted` = 0 ;- JSON 格式结果集
{ "requestId": "tm5zrnaq4c", "err": null, "res": { "updateResult": { "count": 3 } }, "success": true}删除: 更新单模型数据
- DS API写法
// 下面这段逻辑适用于FuncBooleanResult result = DS.delete(orderToDelete);// 下面这段逻辑适用于Flowfinal BooleanResult result = DS.delete(orderToDelete);- 生成的T-SQL
delete from `trade_OrderBo` where `id` = 1- 实际执行的SQL
delete from `trade__order_b_o` where ( `id` = 1 ) AND `isDeleted` = 0 ;- JSON 格式结果集
{ "requestId": "fuo7p5pjvm", "err": null, "res": { "deleteResult": { "count": 1 } }, "success": true}查询: 通过is null条件查询模型
- DS API写法
OrderLineBO resultOrderLine = DS.findOne(OrderLineBO.class, "*", "orderLineTitle is null");- TSQL-DSL
Query query = TSQL.select(TSQL.field("*")) .select(TSQL.field(OrderLineBO.order_field, "*")) .from(OrderLineBO.class) .where(TSQL.field(OrderLineBO.orderLineTitle_field).isNull());
OrderLineBO resultOrderLine = DS.findOne(query);- 生成的T-SQL
SELECT *, `order`.* FROM `trade_OrderLineBO` WHERE `orderLineTitle` is null;- 实际执行的SQL
SELECT `id`, `orderLineTitle`, `updatedAt`, `createdAt`, `isDeleted`, `deletedAt`, `UpdatedBy` AS `updatedBy`, `CreatedBy` AS `createdBy`, `order` AS `order`FROM `trade__order_line_b_o`WHERE (`orderLineTitle` IS NULL) AND `isDeleted` = 0;场景四: JOIN查询
当模型间不存在Link,LinkMany或者LookUp关系时,但是仍然需要进行关联查询,TSQL也提供了JOIN支持,下面简单举例
普通leftJoin查询
- TSQL-DSL
Query joinQuery = TSQL.select(TSQL.field("company", "*")) .select(TSQL.field("staff", "*")) .from(TSQL.table(Company.class).as("company")) .leftJoin(TSQL.table(Staff.class).as("staff")) .on(TSQL.field("company", Company.name_field).eq(TSQL.field("staff", Staff.staffName_field))) .where(TSQL.field("company", Company.code_field).eq("abc")); List<Map<String, Object>> result = DS.find(joinQuery);- 生成的TSQL
select company.*, staff.*from base_Company as companyleft join base_Staff as staff on company.companyName = staff.staffNamewhere company.code = 'abc'- 实际执行的SQL
select company.*, staff.*from base__company as companyleft join base__staff as staff on company.companyName = staff.staffNamewhere company.code = 'abc'innerJoin和rightJoin类似
包含分页的Join查询
如果TSQL包含JOIN语句,是无法使用DS类中提供的page相关接口的,可以通过如下方案解决: 分页查询包括两部分,一是查询分页总数,二是查询当前页数据,page接口内部自动生成了查询total的sql,所以在不使用page接口时我们要自己按需查询total (1) 只查询主模型数据 如:
- TSQL-DSL
Page page = new Page();Query countQuery = TSQL.selectCount() .from(TSQL.table(Company.class).as("company")) .leftJoin(TSQL.table(Staff.class).as("staff")) .on(TSQL.field("company", Company.name_field).eq(TSQL.field("staff", Staff.staffName_field))) .where(TSQL.field("company", Company.code_field).eq("abc"));
long total = DS.count(countQuery);
Query joinQuery = TSQL.select(TSQL.field("company", "*")) .from(TSQL.table(Company.class).as("company")) .leftJoin(TSQL.table(Staff.class).as("staff")) .on(TSQL.field("company", Company.name_field).eq(TSQL.field("staff", Staff.staffName_field))) .where(TSQL.field("company", Company.code_field).eq("abc")) .limit(page.first(), page.limit());
List<Company> data = DS.findAll(joinQuery);return new Paging(total, data);- 生成的TSQL
select count(1)from base_Company as companyleft join base_Staff as staff on company.companyName = staff.staffNamewhere company.code = 'abc';
select company.*from base_Company as companyleft join base_Staff as staff on company.companyName = staff.staffNamewhere company.code = 'abc' limit 1, 10;- 实际执行的SQL
select count(1)from base__company as companyleft join base__staff as staff on company.companyName = staff.staffNamewhere company.code = 'abc';
select company.*from base__company as companyleft join base__staff as staff on company.companyName = staff.staffNamewhere company.code = 'abc' limit 1, 10;(2) 既查询主模型数据也查询被JOIN模型的数据 如:
- TSQL-DSL
Page page = new Page(); Query countQuery = TSQL.selectCount() .from(TSQL.table(Company.class).as("company")) .leftJoin(TSQL.table(Staff.class).as("staff")) .on(TSQL.field("company", Company.name_field).eq(TSQL.field("staff", Staff.staffName_field))) .where(TSQL.field("company", Company.code_field).eq("abc"));long total = DS.count(countQuery);
Query joinQuery = TSQL.select(TSQL.field("company", "*")) .select(TSQL.field("staff", "*")) .from(TSQL.table(Company.class).as("company")) .leftJoin(TSQL.table(Staff.class).as("staff")) .on(TSQL.field("company", Company.name_field).eq(TSQL.field("staff", Staff.staffName_field))) .where(TSQL.field("company", Company.code_field).eq("abc")) .limit(page.first(), page.limit());
List<Company> data = DS.findAll(joinQuery);return new Paging(total, data);- 生成的TSQL
select count(1)from base_Company as companyleft join base_Staff as staff on company.companyName = staff.staffNamewhere company.code = 'abc';
select company.*, staff.*from base_Company as companyleft join base_Staff as staff on company.companyName = staff.staffNamewhere company.code = 'abc' limit 1, 10;- 实际执行的SQL
select count(1)from base__company as companyleft join base__staff as staff on company.companyName = staff.staffNamewhere company.code = 'abc';
select company.*, staff.*from base__company as companyleft join base__staff as staff on company.companyName = staff.staffNamewhere company.code = 'abc' limit 1, 10;场景五:怎么使用JSON函数
JSON_CONTAINS
假如现在有下面的数据,期望筛选出username包含”a”值的数据
username [“a”, “b”, “c”]
TSQL DSL组装方式
Query query = TSQL.select(TSQL.field("id")) .from(User.class) .where(TSQL.condition("JSON_CONTAINS(`username`, \"a\")"));TSQL
select * from base_User where JSON_CONTAINS(`username`, '"a"');JSON_CONTAINS过滤多值写法
Query query = TSQL.select(TSQL.field("id")) .from(User.class) .where(TSQL.condition("JSON_CONTAINS(`nickname`, JSON_ARRAY("1","2","3"))"));如果值为下面格式,期望筛选出nickname包含1的数据
nickname [1, 2, 3]
TSQL DSL组装方式
Query query = TSQL.select(TSQL.field("id")) .from(User.class) .where(TSQL.condition("JSON_CONTAINS(`nickname`, 1)"));TSQL
select * from base_User where JSON_CONTAINS(`nickname`, '1');JSON_ARRAY_APPEND
assistIds为辅助核算值,期望通过JSON_ARRAY_APPEND处理科目新增辅助核算的时候添加辅助核算值
if(CollectionUtils.isNotEmpty(assistIds)){ updateSql.set(TSQL.field(VoucherLineBO.assistAccountingIds_field), (Object) TSQL.field("JSON_ARRAY_APPEND(`"+VoucherLineBO.assistAccountingIds_field+"`, '$', "+String.join(", '$', ", assistIds.stream().map(Object::toString).collect(Collectors.toSet()))+")", Object.class));}TSQL
set `assistAccountingIds` = JSON_ARRAY_APPEND(`assistAccountingIds`, '$', 642035)查询ES
DS目前会有两种方式查询ES中的数据,一是会根据TSQL生成ES DSL去请求ES服务器,二是通过SearchQuery对象直接生成ES DSL去查询ES服务器,下面的文档也会写出两种方式实现同一功能的不同写法。另外根据业务需求,目前所有的查询都是分页查询。具体的Search API调用方法可以参考文档: 《Search API查询ES》
3. 最佳实践
3.1 查询
对于查询类的TSQL,尽可能使用预编译模式,因为DataStore会缓存原始SQL以及对应的逻辑执行计划,走预编译模式的SQL,只会在第一次请求时候走一次语法树的解析,这个解析过程需要1-5ms的开销,因此推荐大家尽量使用预编译模式。
- 推荐的DS API写法
List<OrderBO> resultOrderList = DS .findAll( OrderBO.class, "*, orderLineList.*", "orderTitle = ?", order.getOrderTitle() );- 不推荐的DS API写法
List<OrderBO> resultOrderList = DS .findAll( OrderBO.class, "*, orderLineList.*", "orderTitle = " + order.getOrderTitle() );区别点在于下面的写法直接把condition拼接到了where条件中,没有用?占位符。