sql数据源
jxTMS中有两种数据读取方式:
- 内置函数法,jxTMS中所有数据库中的数据表都对应为一个同名的ORM数据类,其都继承自同一个orm类,jxTMS为这些orm对象定义了一些基本的访问接口【本文不涉及】
- sql查询,为了便于开发者使用,jxTMS提供了一种类sql语法的文本定义的数据查询语句,开发者可用其定义自己的数据查询,jxTMS称之为数据源。jxTMS在加载模块时,会将sql文件中的每一条类sql语句,翻译为内部的SelectSql对象,保存到ORG对象的高速缓存中,在使用时复制后提供给capa,然后根据用户的操作可以对其中的变量赋值、添加查询条件等,然后动态生成相应的标准sql语句提交给数据库执行查询。如果指定了查询结果为orm对象格式,则自动为每行数据生成一个orm对象,然后根据orm类的定义将行中各列数据转换为相应的orm对象同名属性的值
类sql定义的语法如下:
sql 数据源名
from 数据表名1 as 表别名1 , 数据表名2 as 表别名2 ,......
select 所要获取的数据列名
where 条件组合
orderBy 哪个表的别名.哪列 DESC?
注:sql文件中的每条语句都必须用英文分号分隔
其中,数据源名在同一个空间中不能重复。和标准sql语句最大的不同,jxTMS的类sql语法就是from在select之前,这一点和.net的linQ是一样的,原因就在于这个语法是按定义顺序依次为SelectSql对象设置参数的,如果select在前,则其就不知道所引用的表别名是否在from子句中定义了,而如果没有定义则无法在此时就掷出异常以提示定义错误,为了避免这个问题那就需要二次扫描,这样的效率较低。所以jxTMS就将from子句移到了select子句之前。
select所要获取的数据列名,有两种定义格式:
- 查询某个表的所有列【表别名.all】,这一方式最为常用,一般用于将查询出来的每行数据都自动生成为相应的orm对象
- 查询多个表的个别列【表别名1.列名1 as 别名1,表别名2.列名2 as 别名2,表别名3.列名3 as 别名3,......】,查询结果是将查询出来的数据生成一个json数组,查询结果的每一行就对应该数组中的每一行:[{rowid:0,别名1:值1,别名2:值2,别名3:值3,...},{rowid:1,别名1:值11,别名2:值22,别名3:值33,...},...]
条件组合是and连接的比较表达式。由于或连接的逻辑表达式可以变换为等价的与连接逻辑表达式【其中的取反操作可通过值比较算符的取反来实现】,因此为了避免过于复杂的表达式语法导致的混乱【主要是逻辑算符之间的优先级问题、以及括号的吸收问题,导致jxTMS想将其准确翻译为对应的sql语句较为困难,笔者不愿在此问题上投入过多的精力】,所以jxTMS最终强制只能采用and逻辑算符连接。
比较表达式有三种:
- 列与固定值的比较
如:
ta1.Name=='john' and ta1.NoUsed==false and ta2.Number==7 and ta3.FolatNumber==12.34
- 列与变量的比较,如ta1.ID==myID
- 不同表之间列与列的相等判定,如ta1.ID==tr.ObjID
前两种比较算符都支持:等于【==】、不等【!=】、大于【>】、大于等于【>=】、小于【<】、小于等于【<=】、相似【like】共七种。
注1:标准sql语法中的等于只是一个等于号,而jxTMS中单等于意为赋值,双等于号才意为相等
注2:相似是字符串的开始部分是否吻合,即实质是头包含
注3:由于存在相似比较符,所以以其组成的or连接,是无法等价转换为and连接的
注4:全文搜索字段的匹配检测是独立的比较算符,目前类sql语法不支持,而只能用在条件搜索的两函数中手工设置
前两种的区分,就在于有无单引号,即:
【col1==myID】是col1在查询执行前需先给数据源的myID变量赋值,然后其在查询时才会检查所赋的值
【col1=='myID'】是col1的值等于'myID'的才会被查询出来。
列与列的相等主要用于多表联合查询时,将两个表关联起来。
orderBy子句目前只支持一个列,形如ta1.Name,没有此子句时,默认是每行数据插入的顺序,DESC【四个字母都是大写】指示按该列值的降序来排列,如果省略则按升序排列。
注:orderBy中间没有空格。而且所有关键字【英文的】必须按上面的文法书写,不支持不区分大小写
sql数据源的使用
jxTMS已经提供了标准的分页查询、条件搜索的工作框架:
- 开发者先定义一个待查询对象列表的web界面【如demo中sales.order模块中的销售列表界面,codeDefine目录下,demo->sales->order目录下web文件中的listSalesOrder】,一般该界面包括两块:一个用于设置查询条件的容器表【如listSalesOrdert1】、一个用于显示查询结果的数据表【如listSalesOrdert2】。然后为数据表指定三个属性:
如listSalesOrdert2中定义的是:
pagination=true, //允许启用分页
query=search, //指定查询命令,必须是search
queryParam={'listTable':'listSalesOrdert2'}, //指定的查询结果显示数据表名
此外,因为分页查询的第一步是请求后台为当前查询计算数据库中符合条件的数据行数,所以还需为该数据表绑定约定好的总行数名tableTotalCount:
web listSalesOrdert2 bind tableTotalCount
注:tableTotalCount是所有分页的数据表都必须绑定的,jxTMS的机制决定了一个界面中只应有一个分页的数据表,所以tableTotalCount的重复不影响数据表的正常工作
- 在sql文件中定义一个数据源
如:
sql listOrder
from extOrder as ta
select ta.all
orderBy ta.CreateTime DESC;
- 在op.py中定义一个显示该界面的入口
如:
@biz.OPDescr
def op1(json):
json.setShortcut('销售订单'.decode('utf-8'),'订单查询'.decode('utf-8'))
json.module('sales').capaname('order')
json.disp('listSalesOrder').setParam('dispType','list').setParam('dataSource','sales.listOrder')
json.setParam('objType','extOrder')
json.role('总经理'.decode('utf-8'),'销售部经理'.decode('utf-8'))
其中必须指定两个参数:dispType='list'【必须这么设置】,以及dataSource='sales.listOrder',指出所引用的数据源就是listOrder,注意,这里要用数据源的全名。
然后无需开发者输入任何代码,就自动完成了订单查询功能:点击快捷功能树中的【销售订单->订单查询】即自动显示web中定义的listSalesOrder界面,并分页加载订单数据,但如果订单数据需要转换或添加诸如【查看订单详情】这样的针对每个订单的操作,则还需继承相应的转换函数来完成:
#列表查询时,如果是用select ta.all的方式生成一个orm数据对象的情况
#则调用本函数来针对web中数据表各列进行针对性的设置
def dispAffairInfo(self,db,ctx,json, jo):
json.set("orderID", jo.ID)
json.set("orderType", jo.Type)
json.set("orderName", jo.Name)
json.set("custom", jo.Custom)
json.set("sales",Relation.getObj(db.getDBConn(),jo.ID,'relSales2Order','people').Name)
json.set('orderState',jo.State)
json.set('amount',jo.Amount)
#为查看按钮生成一个动态的a串以供用户点击查看该订单的信息
json.set("op1",self.getViewA(ctx,jo))
注:大家可通过点击查看显示效果以及自己录入的订单信息来理解其是如何工作的
但自动完成的不包括条件查询功能,为了能实现条件查询,开发者需要重载两个函数:
#根据用户输入动态增加查询条件时,重载:
def setSearchCondition(self, db, ctx):
cn = self.getInputString('customName')
if not utils.isNull(cn):
#self.sql就是准备执行的SelectSql对象,jxTMS已经准备完毕,开发者只需检查用户是否输入,然后根据用户输入与否来决定是否添加相应的查询条件即可
self.sql.addContion('salesOrder', 'Custom', jxCompare.Match,cn)
#如果数据源是一个通用查询,在执行时根据上下文的具体情况通过变量来实现针对性的查询时,重载:
def setSearchConditionVarValue(self, db, ctx):
if self.dataSource == 'sales.listMyOrder':
#不同人查我的订单,自然是不同,这就需要用上下文中的执行者ID来为数据源中的变量赋值
#self.infoSearch是self.sql设置完毕后所生成的执行体
self.infoSearch.setVar('salesID',ctx.getCaller().id())
目前,jxTMS已经打包为云服务器镜像,开发者开箱即用:
jxTMS-腾讯云市场market.cloud.tencent.com