JRT的设计目标就是多数据库支持,对于爬行周边数据提供DolerGet解决爬取多维数据问题。但是对于通过父表字段筛选子表数据就不能通过DolerGet取数据了,因为查询到的父表数据没有子表数据的ID。
比如下面表:
我需要按登记号查询这个登记号的报告数据,如果先查询父表数据,再循环一个个查子数据,那么数据多了之后需要交互数据库太多了,就会慢,这种情况就需要级联查询,来减少交互次数。而父表数据也拿不到子表的ID,因而不能利用DolerGet特性。
所以需要ORM来支持视图查询,常规的一般是提供SQL语句执行的api直接执行SQL。但是这样跨数据库就不能无缝支持了,为此需要提供一种独立于数据库的视图查询方法。
首先定义实体来描述级联关系
然后定义一个基类来存储视图描述数据
然后抽取一个所有视图实体要实现的接口供ORM得到视图描述信息
定义一个注解来标记视图
定义视图
ORM根据视图注解调用获取视图信息接口得到信息后组装视图SQL
/*** 构造视图的SQL语句* @param factory* @param tableInfo* @param model* @throws Exception*/private static void MakeViewTableInfo(IDbFactory factory,TableInfo tableInfo,Object model) throws Exception{if(model==null){model=tableInfo.ModelClass.getConstructor().newInstance();}BaseViewInterface base=(BaseViewInterface)model;BaseView view=base.GetView();StringBuilder tmpSb=new StringBuilder();tmpSb.append("(select ");String fromSql=" from ";boolean hasAddCol=false;//得到视图列信息Field[] viewFields = tableInfo.ModelClass.getDeclaredFields();HashMap<String,Field> viewFiledMap=new HashMap<>();for(Field f:viewFields){viewFiledMap.put(f.getName(),f);}//记录已经添加的列,避免重复添加HashMap<String,Boolean> hasAddColMap=new HashMap();for(int i=0;i<view.TableList.size();i++){ViewModelDto one=view.TableList.get(i);if(one.LinkType==null||one.LinkType.isEmpty()){one.LinkType="left";}String oneModelName=one.ModelClass.getSimpleName();if(i==0) {fromSql += " " + factory.DealTableName(GetTableName(one.ModelClass)) + " "+oneModelName+" ";}else{fromSql += one.LinkType+" join " + factory.DealTableName(GetTableName(one.ModelClass)) + " " + oneModelName+" on "+oneModelName+"."+one.LinkCurCol+"="+one.PerModelClass.getSimpleName()+"."+one.LinkPerCol+" ";}//得到列信息Field[] declaredFields = one.ModelClass.getDeclaredFields();//指定了查询列HashMap<String,Boolean> colMap=new HashMap<>();if(one.Cols!=null&&!one.Cols.isEmpty()){String [] colArr=one.Cols.split(",");for(String col:colArr){if(col.isEmpty()){continue;}colMap.put(col,true);}}//得到查询列for (int j = 0; j < declaredFields.length; j++) {if(colMap.size()>0&&!colMap.containsKey(declaredFields[j].getName())){continue;}String colName=declaredFields[j].getName();if(!viewFiledMap.containsKey(colName)){continue;}Field colFile=viewFiledMap.get(colName);String transName="";if(one.ColTrans!=null&&one.ColTrans.containsKey(colName)){transName=" as "+factory.DealPropertyName(one.ColTrans.get(colName));}//避免重复列名if(hasAddColMap.containsKey(colName)){continue;}JRT.DAL.ORM.Common.ColumnInfo col = new JRT.DAL.ORM.Common.ColumnInfo();FrekeyAttribute fk = colFile.getAnnotation(FrekeyAttribute.class);col.FkInfo = fk;col.Name = colName;col.ColType = colFile.getType();col.FieldInfo = colFile;tableInfo.ColList.add(col);//特殊列Annotation dateAttribute = colFile.getAnnotation(DateAttribute.class);//日期0,时间1,布尔2if (dateAttribute != null) {tableInfo.SpCol.put(col.Name, 0);}Annotation timeAttribute = colFile.getAnnotation(TimeAttribute.class);if (timeAttribute != null) {tableInfo.SpCol.put(col.Name, 1);}Annotation boolAttribute = colFile.getAnnotation(BoolAttribute.class);if (boolAttribute != null) {tableInfo.SpCol.put(col.Name, 2);}//根据IdAttribute注解得到表ID字段IdAttribute id = colFile.getAnnotation(IdAttribute.class);if (id != null) {JRT.DAL.ORM.Common.IdInfo idInfo = new JRT.DAL.ORM.Common.IdInfo();idInfo.Key = col.Name;idInfo.Value = col.Value;tableInfo.ID = idInfo;}if(hasAddCol==false) {tmpSb.append(oneModelName + "." + factory.DealPropertyName(col.Name));}else{tmpSb.append("," + oneModelName + "." + factory.DealPropertyName(col.Name));}hasAddColMap.put(col.Name,true);hasAddCol=true;}}tmpSb.append(" "+fromSql+")");tableInfo.VewSql=tmpSb.toString();}
视图实体和正常单表实体一样查询数据
测试效果
这样基于DolerGet和视图查询开发业务就可以游刃有余了