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,布尔2
if (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和视图查询开发业务就可以游刃有余了