Mybatis(攔截器實現)通用mapper及全ORM實現(四)
到目前為止,我們通過mybatis的攔截器完成了一些基礎mapper的功能,接下來我們來看看如何能夠實現一個物件關係對映的全ORM操作。
實體與表、列的定義已經完成了,那剩下要做的就是: 1、定義如何通過物件方式編寫sql語句 2、把查詢物件轉譯成sql去查詢 3、把查詢結果轉化成實體物件
我們先看看mybatisext關於查詢物件的一些類關係:
SqlStatement介面
所有查詢物件必須實現一下幾個方法: 1、getSqlWrapper() 返回一個sql資訊物件包括sql語句和裡面的相關引數map資訊 2、getResultMap() 返回這個查詢sql的返回結果中每個欄位對應的實體類及其中的屬性 3、getFormatSqlWrapper() 返回一個標準的sql資訊物件,與getSqlWrapper不同是sql語句裡面不會有需要替換的變數,以mysql為例引數會替換成?,幷包括根據引數順序的引數值陣列 4、getFormatSqlReplacement() sql中引數替代自負,預設?
package cw.frame.mybatisext.base; import java.util.HashMap; import java.util.Map; public class SqlWrapper { private String sql; private Map<String, Object> parameters = new HashMap<String, Object>(); public SqlWrapper(){} public SqlWrapper(String sql){ this.sql = sql; } public SqlWrapper(String sql, Map<String, Object> parameters){ this.sql = sql; this.parameters = parameters; } public Map<String, Object> getParameters() { return parameters; } public String getSql() { return sql; } public void setParameters(Map<String, Object> parameters) { this.parameters = parameters; } public void setSql(String sql) { this.sql = sql; } }
package cw.frame.mybatisext.base; import cw.frame.mybatisext.base.entity.TableInfo; import java.util.*; public class ResultMap { private TableInfo tableInfo; private Map<String, String> resultMap; private Map<String, ResultMap> subResultMap; public ResultMap(TableInfo tableInfo){ this.tableInfo = tableInfo; this.resultMap = new HashMap<String, String>(); this.subResultMap = null; } public void addResultMap(String resultName, String propertyName){ this.resultMap.put(resultName, propertyName); } /** * 新增子結果對映 * @param subResultMap 子結果map物件 * @param resultPropertyName 結果儲存欄位 */ public void addSubResultMap(ResultMap subResultMap, String resultPropertyName){ if (this.subResultMap == null){ this.subResultMap = new HashMap<String, ResultMap>(); } this.subResultMap.put(resultPropertyName, subResultMap); } public Map<String, String> getResultMap(){ return this.resultMap; } public boolean hasSubResultMap(){ if (this.subResultMap != null && this.subResultMap.size() > 0){ return true; } else { return false; } } public Map<String, ResultMap> getSubResultMap() { return subResultMap; } public TableInfo getTableInfo(){ return this.tableInfo; } }
BaseSqlStatement抽象類
SqlStatement的實現類,定義了基礎mapper中需要攔截的sql語句常量、引數名稱常量,和一個抽象方法prepare()
getFormatSqlWrapper() -> getSqlWrapper() -> prepare()
子類需要完善的prepare()方法要做的事情也就是建立一個SqlWrapper物件
package cw.frame.mybatisext.base;
import cw.frame.mybatisext.SqlStatement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public abstract class BaseSqlStatement implements SqlStatement {
public static final String OPERATE_TYPE_NAME_PRE = "mybatisext.";
public static final String OPERATE_TYPE_ADD_ONE = OPERATE_TYPE_NAME_PRE + "addOne";
public static final String OPERATE_TYPE_ADD_MANY = OPERATE_TYPE_NAME_PRE + "addMany";
public static final String OPERATE_TYPE_REMOVE_BY_ID = OPERATE_TYPE_NAME_PRE + "removeById";
public static final String OPERATE_TYPE_REMOVE_BY_IDS = OPERATE_TYPE_NAME_PRE + "removeByIds";
public static final String OPERATE_TYPE_REMOVE = OPERATE_TYPE_NAME_PRE + "remove";
public static final String OPERATE_TYPE_UPDAT_BY_ID = OPERATE_TYPE_NAME_PRE + "updateById";
public static final String OPERATE_TYPE_UPDATE = OPERATE_TYPE_NAME_PRE + "update";
public static final String OPERATE_TYPE_GET_BY_ID = OPERATE_TYPE_NAME_PRE + "findById";
public static final String OPERATE_TYPE_GET_BY_IDS = OPERATE_TYPE_NAME_PRE + "findByIds";
public static final String OPERATE_TYPE_GET_ONE = OPERATE_TYPE_NAME_PRE + "getOne";
public static final String OPERATE_TYPE_GET_MANY = OPERATE_TYPE_NAME_PRE + "getMany";
public static final String OPERATE_TYPE_GET_PAGE = OPERATE_TYPE_NAME_PRE + "getPage";
public static final String OPERATE_PARAM_ENTITY = "entity";
public static final String OPERATE_PARAM_ENTITIES = "entities";
public static final String OPERATE_PARAM_PRIMARY_KEY = "id";
public static final String OPERATE_PARAM_PRIMARY_KEYS = "ids";
public static final String OPERATE_PARAM_SQLSTATEMANT = "sqlStatement";
public static final String OPERATE_PARAM_PAGER = "pager";
private SqlWrapper sqlWrapper;
private ResultMap resultMap;
private FormatSqlWrapper formatSqlWrapper = null;
@Override
public SqlWrapper getSqlWrapper(){
if (this.sqlWrapper == null){
this.prepare();
}
return this.sqlWrapper;
}
@Override
public ResultMap getResultMap(){
return this.resultMap;
}
@Override
public FormatSqlWrapper getFormatSqlWrapper(){
if (this.formatSqlWrapper == null){
this.formatSql();
}
return this.formatSqlWrapper;
}
public void setResultMap(ResultMap resultMap){
this.resultMap = resultMap;
}
public String getParameterName(String tableName, String propertyName){
StringBuilder sb = new StringBuilder();
sb.append("#{");
if(tableName != null && !tableName.isEmpty()){
sb.append(tableName).append(".");
}
sb.append(propertyName);
sb.append("}");
return sb.toString();
}
protected void setSqlWrapper(String sql) {
this.sqlWrapper = new SqlWrapper(sql);
}
protected void setSqlWrapper(String sql, Map<String, Object> parameters) {
this.sqlWrapper = new SqlWrapper(sql, parameters);
}
protected void setSqlWrapper(SqlWrapper sqlWrapper) {
this.sqlWrapper = sqlWrapper;
}
protected void unsetSqlWrapper(){
this.sqlWrapper = null;
}
protected SqlWrapper combineSqlWrappers(List<SqlStatement> sqlStatements, String joinStr){
if (sqlStatements.size() == 0){
return new SqlWrapper();
}
StringBuilder sb = new StringBuilder();
Map<String, Object> parameters = new HashMap<String, Object>();
for(SqlStatement sqlStatement : sqlStatements){
if (sb.length() > 0){
sb.append(joinStr);
}
SqlWrapper sqlWrapper = sqlStatement.getSqlWrapper();
sb.append(sqlWrapper.getSql());
parameters.putAll(sqlWrapper.getParameters());
}
return new SqlWrapper(sb.toString(), parameters);
}
protected abstract void prepare();
private void formatSql(){
StringBuffer sbSql = new StringBuffer();
List<Object> values = new ArrayList<Object>();
SqlWrapper sqlWrapper = this.getSqlWrapper();
Pattern pattern = Pattern.compile("#\\{\\S+?\\}");
Matcher matcher = pattern.matcher(sqlWrapper.getSql());
while (matcher.find()){
matcher.appendReplacement(sbSql, this.getFormatSqlReplacement());
values.add(sqlWrapper.getParameters().get(matcher.group()));
}
matcher.appendTail(sbSql);
this.formatSqlWrapper = new FormatSqlWrapper(sbSql.toString(), values);
}
}
接下來就是定義具體的查詢物件了,mybatisext把一個查詢拆分成幾個部分並進行不同的類封裝: 1、select欄位部分 2、表連線部分 3、單個條件欄位部分 4、單個分組group欄位部分 5、單個having欄位你部分 6、單個order欄位排序部分 7、多個條件、排序、分組、連線的部分
我們來逐一看下程式碼
package cw.frame.mybatisext.provider.mysql.statement;
import cw.frame.mybatisext.base.BaseSqlStatement;
import cw.frame.mybatisext.base.ResultMap;
import cw.frame.mybatisext.base.entity.BaseExtEntity;
import cw.frame.mybatisext.base.entity.ColumnInfo;
import cw.frame.mybatisext.base.entity.TableInfo;
import cw.frame.mybatisext.provider.mysql.ExpressionExplain;
import cw.frame.mybatisext.provider.mysql.ExpressionResult;
import java.util.*;
public class SelectStatement extends BaseSqlStatement {
private Class<? extends BaseExtEntity> entityClassType;
private Set<String> selectPropertyNames = new TreeSet<String >();
private Map<String, String> selectPropertyNameMap = new HashMap<String, String>();
private TableInfo tableInfo;
private String aliasTableName;
private Map<String, String> propertyResultMap = new HashMap<String, String>();
private ResultMap resultMap;
public SelectStatement(Class<? extends BaseExtEntity> entityClassType, String aliasTableName){
this.entityClassType = entityClassType;
this.aliasTableName = aliasTableName;
this.tableInfo = TableInfo.getTableInfo(this.entityClassType);
this.resultMap = new ResultMap(this.tableInfo);
this.setResultMap(this.resultMap);
}
/**
* 設定查詢列
* @param propertyNames propertyName, max(#{propertyName})等
*/
public void select(String... propertyNames){
for (String propertyName : propertyNames){
if (propertyName.equals("*")){
for (ColumnInfo columnInfo : this.tableInfo.getColumnns()){
this.selectPropertyNames.add(columnInfo.getPropertyName());
}
break;
} else {
this.selectPropertyNames.add(propertyName);
}
}
this.unsetSqlWrapper();
}
/**
* 設定查詢列
* @param propertyName propertyName, max(#{propertyName})等
* @param resultPropertyName 結果返回儲存屬性欄位
*/
public void selectAs(String propertyName, String resultPropertyName){
this.selectPropertyNameMap.put(propertyName, resultPropertyName);
}
/**
* 設定查詢列
* @param propertyNameMap k:propertyName propertyName, max(#{propertyName})等,v:結果返回儲存屬性欄位
*/
public void selectAs(Map<String, String> propertyNameMap){
this.selectPropertyNameMap.putAll(propertyNameMap);
}
public TableInfo getTableInfo(){
return this.tableInfo;
}
public boolean hasSelectFields(){
return this.selectPropertyNames.size() > 0;
}
public String getAliasTableName() {
return aliasTableName;
}
public Map<String, String> getPropertyResultMap() {
return propertyResultMap;
}
@Override
protected void prepare(){
StringBuilder sb = new StringBuilder();
for (String propertyName : this.selectPropertyNames){
this.buildSelectItemPartSql(sb, propertyName, null);
}
for (String propertyName : this.selectPropertyNameMap.keySet()){
this.buildSelectItemPartSql(sb, propertyName, this.selectPropertyNameMap.get(propertyName));
}
// 查詢所有欄位
if (sb.length() == 0){
for (String propertyName : this.tableInfo.getPropertyNames()){
this.buildSelectItemPartSql(sb, propertyName, null);
}
}
String sql = sb.toString();
this.setSqlWrapper(sql);
}
private void buildSelectItemPartSql(StringBuilder sb, String selectFieldString, String resultProperty){
if (sb.length() != 0){
sb.append(",");
}
ExpressionResult expressionResult = ExpressionExplain.explain(selectFieldString, this);
ColumnInfo columnInfo = expressionResult.getColumn();
if (expressionResult.isExpression()){
sb.append(expressionResult.getResult());
} else {
sb.append(this.aliasTableName).append(".`");
sb.append(columnInfo.getColumnName()).append("`");
}
String asName;
String resultPropertyName;
if (resultProperty == null || resultProperty.isEmpty()){
asName = this.aliasTableName + "_" + columnInfo.getColumnName();
resultPropertyName = columnInfo.getPropertyName();
} else {
ColumnInfo resultColumn = this.tableInfo.getColumnByPropertyName(resultProperty);
resultPropertyName = resultProperty;
if (resultColumn.isDbColumn()){
asName = this.aliasTableName + "_" + resultColumn.getPropertyName();
} else {
asName = this.aliasTableName + "_" + resultPropertyName;
}
}
sb.append(" ").append(asName);
this.propertyResultMap.put(resultPropertyName, asName);
this.resultMap.addResultMap(asName, resultPropertyName);
}
}
通過SelectStatement可以設定需要查詢的列,也可以指定查詢列結果別名(column1 as xxx),並對自定義了一個別名:表別名_列名(或指定的別名),最終把這些別名和實體對應關係記錄在一個ResultMap類裡
package cw.frame.mybatisext.provider.mysql.statement;
import cw.frame.mybatisext.base.BaseSqlStatement;
import cw.frame.mybatisext.base.SqlWrapper;
import cw.frame.mybatisext.enumeration.JoinType;
import cw.frame.mybatisext.provider.mysql.MySqlStatement;
import java.util.HashMap;
import java.util.Map;
public class SingleJoinStatement extends BaseSqlStatement {
private SelectStatement fromSelectStatement;
private Object toStatement;
private JoinType joinType;
private Map<String, String> joinRelationshipMap = new HashMap<String, String>();
public SingleJoinStatement(SelectStatement fromSelectStatement, SelectStatement toSelectStatement, JoinType joinType){
this.fromSelectStatement = fromSelectStatement;
this.toStatement = toSelectStatement;
this.joinType = joinType;
}
public SingleJoinStatement(SelectStatement fromSelectStatement, MySqlStatement toMySqlStatement, JoinType joinType){
this.fromSelectStatement = fromSelectStatement;
this.toStatement = toMySqlStatement;
this.joinType = joinType;
}
public void setRelationship(String fromPropertyName, String toPropertyName){
this.joinRelationshipMap.put(fromPropertyName, toPropertyName);
}
@Override
protected void prepare(){
StringBuilder sb = new StringBuilder();
Map<String, Object> parameters = new HashMap<String, Object>();
SelectStatement toSelectStatement = null;
MySqlStatement toMySqlStatement = null;
for (String fromPropertyName : this.joinRelationshipMap.keySet()){
String toPropertyName = this.joinRelationshipMap.get(fromPropertyName);
if (sb.length() == 0){
sb.append(this.getJoinTypeSqlString(this.joinType)).append(" ");
if (this.toStatement instanceof SelectStatement){
toSelectStatement = (SelectStatement)this.toStatement;
String toTableAsName = toSelectStatement.getAliasTableName();
sb.append("`").append(toSelectStatement.getTableInfo().getTableName()).append("`");
sb.append(" ").append(toTableAsName);
} else {
// 連線子查詢
toMySqlStatement = (MySqlStatement)this.toStatement;
String toTableAsName = toMySqlStatement.getSelectStatement().getAliasTableName();
SqlWrapper wrapper = toMySqlStatement.getSqlWrapper();
parameters.putAll(wrapper.getParameters());
sb.append("(").append(wrapper.getSql()).append(")");
sb.append(" ").append(toTableAsName);
}
sb.append(" on ");
} else {
sb.append(" and ");
}
sb.append(this.fromSelectStatement.getAliasTableName()).append(".`");
sb.append(this.fromSelectStatement.getTableInfo().getColumnByPropertyName(fromPropertyName).getColumnName());
sb.append("`=");
if (toSelectStatement != null){
sb.append(toSelectStatement.getAliasTableName()).append(".").append("`");
sb.append(toSelectStatement.getTableInfo().getColumnByPropertyName(toPropertyName).getColumnName());
sb.append("`");
} else {
sb.append(toMySqlStatement.getSelectStatement().getAliasTableName());
sb.append(".`");
sb.append(toMySqlStatement.getSelectStatement().getPropertyResultMap().get(toPropertyName));
sb.append("`");
}
}
this.setSqlWrapper(new SqlWrapper(sb.toString(), parameters));
}
private String getJoinTypeSqlString(JoinType joinType){
String str;
switch (joinType){
case LEFT_JOIN:
str = "left join";
break;
case INNER_JOIN:
str = "inner join";
break;
case RIGHT_JOIN:
str = "right join";
break;
default:
str = "inner join";
break;
}
return str;
}
}
SingleJoinStatement支援了兩個表的連線和表與一個查詢物件(子查詢)的連線
package cw.frame.mybatisext.provider.mysql.statement;
import cw.frame.mybatisext.base.BaseSqlStatement;
import cw.frame.mybatisext.SqlStatement;
import cw.frame.mybatisext.base.SqlWrapper;
import cw.frame.mybatisext.base.entity.BaseExtEnum;
import cw.frame.mybatisext.enumeration.ConditionType;
import java.lang.reflect.Array;
import java.util.HashMap;
import java.util.Map;
public class SingleConditionStatement extends BaseSqlStatement {
private ConditionType conditionType;
private String columnName;
private Object propertyValue;
private String tableName = "";
public SingleConditionStatement(String tableName, String columnName, ConditionType conditionType, Object propertyValue){
this.columnName = columnName;
this.conditionType = conditionType;
this.propertyValue = propertyValue;
this.tableName = tableName;
}
public String getColumnName() {
return columnName;
}
public ConditionType getConditionType() {
return conditionType;
}
public Object getPropertyValue() {
return propertyValue;
}
@Override
protected void prepare(){
Map<String, Object> parameters = new HashMap<String, Object>();
StringBuilder sb = new StringBuilder();
String conditionColumnName = "`" + this.columnName + "`";
if (!this.tableName.isEmpty()){
conditionColumnName = this.tableName + "." + conditionColumnName;
}
switch (this.conditionType){
case IN:
sb.append(" find_in_set (").append(conditionColumnName).append(",");
break;
case NOT_IN:
sb.append(" not find_in_set (").append(conditionColumnName).append(",");
break;
case EQUAL:
sb.append(conditionColumnName);
sb.append("=");
break;
case NOT_EQUAL:
sb.append(conditionColumnName);
sb.append("<>");
break;
case GREATER:
sb.append(conditionColumnName);
sb.append(">");
break;
case GREATER_AND_EQUAL:
sb.append(conditionColumnName);
sb.append(">=");
break;
case LESS:
sb.append(conditionColumnName);
sb.append("<");
break;
case LESS_AND_EQUAL:
sb.append(conditionColumnName);
sb.append("<=");
break;
case LIKE:
sb.append(conditionColumnName);
sb.append(" like ");
break;
case NOT_LIKE:
sb.append(conditionColumnName);
sb.append(" not like ");
break;
}
if (this.propertyValue instanceof SqlStatement){
SqlStatement sqlStatement = (SqlStatement) this.propertyValue;
SqlWrapper sqlWrapper = sqlStatement.getSqlWrapper();
String sql = sqlWrapper.getSql();
sb.append(sql);
parameters.putAll(sqlWrapper.getParameters());
} else {
String parameterName = this.getParameterName(this.tableName, this.columnName);
sb.append(parameterName);
if (this.conditionType == ConditionType.IN || this.conditionType == ConditionType.NOT_IN){
if (this.propertyValue.getClass().isArray()){
StringBuilder sbValue = new StringBuilder();
for (int i=0; i<Array.getLength(this.propertyValue); i++){
if (sbValue.length() > 0){
sbValue.append(",");
}
sbValue.append(Array.get(this.propertyValue, i));
}
parameters.put(parameterName, this.getPropertyValue(this.propertyValue).toString());
} else {
parameters.put(parameterName, this.getPropertyValue(this.propertyValue));
}
} else {
parameters.put(parameterName, this.getPropertyValue(this.propertyValue));
}
}
if (this.conditionType == ConditionType.IN || this.conditionType == ConditionType.NOT_IN){
sb.append(")");
}
this.setSqlWrapper(new SqlWrapper(sb.toString(), parameters));
}
private Object getPropertyValue(Object propertyValue){
if (propertyValue instanceof BaseExtEnum){
return ((BaseExtEnum) propertyValue).getValue();
} else {
return propertyValue;
}
}
}
package cw.frame.mybatisext.provider.mysql.statement;
import cw.frame.mybatisext.base.BaseSqlStatement;
import cw.frame.mybatisext.base.SqlWrapper;
public class SingleGroupStatement extends BaseSqlStatement {
private String columnName;
private String tableName = "";
private SqlWrapper sqlWrapper;
public SingleGroupStatement(String columnName){
this.columnName = columnName;
}
public SingleGroupStatement(String columnName, String tableName){
this.columnName = columnName;
this.tableName = tableName;
}
@Override
protected void prepare(){
StringBuilder sb = new StringBuilder();
sb.append(this.tableName).append(".`");
sb.append(this.columnName).append("`");
this.setSqlWrapper(new SqlWrapper(sb.toString()));
}
}
package cw.frame.mybatisext.provider.mysql.statement;
import cw.frame.mybatisext.base.BaseSqlStatement;
import cw.frame.mybatisext.base.SqlWrapper;
import cw.frame.mybatisext.enumeration.OrderType;
public class SingleOrderStatement extends BaseSqlStatement {
private String columnName;
private String tableName = "";
private OrderType orderType = OrderType.DESCENDING;
private SqlWrapper sqlWrapper;
public SingleOrderStatement(String columnName){
this.columnName = columnName;
}
public SingleOrderStatement(String columnName, String tableName){
this.columnName = columnName;
this.tableName = tableName;
}
public SingleOrderStatement(String columnName, OrderType orderType){
this.columnName = columnName;
this.orderType = orderType;
}
public SingleOrderStatement(String columnName, OrderType orderType, String tableName){
this.columnName = columnName;
this.orderType = orderType;
this.tableName = tableName;
}
@Override
protected void prepare(){
StringBuilder sb = new StringBuilder();
sb.append(this.tableName).append(".`");
sb.append(this.columnName).append("`");
if (this.orderType == OrderType.DESCENDING){
sb.append(" desc");
}
this.setSqlWrapper(new SqlWrapper(sb.toString()));
}
}
package cw.frame.mybatisext.provider.mysql.statement;
import cw.frame.mybatisext.base.BaseSqlStatement;
import cw.frame.mybatisext.SqlStatement;
import cw.frame.mybatisext.base.SqlWrapper;
import java.util.ArrayList;
import java.util.List;
public class MutiSqlStatement extends BaseSqlStatement {
private List<SqlStatement> statements;
private String joinStr;
public MutiSqlStatement(String joinStr){
this.statements = new ArrayList<SqlStatement>();
this.joinStr = joinStr;
}
public MutiSqlStatement(List<SqlStatement> statements, String joinStr){
this.statements = statements;
this.joinStr = joinStr;
}
public MutiSqlStatement addStatement(SqlStatement statement){
this.statements.add(statement);
this.unsetSqlWrapper();
return this;
}
@Override
protected void prepare(){
SqlWrapper wrapper = this.combineSqlWrappers(this.statements, this.joinStr);
this.setSqlWrapper(wrapper);
}
}
MutiSqlStatement其實就是多個查詢物件的集合,並把每個查詢物件通過指定的連線字串進行連線,引數進行合併
MysqlStatement
最後,為了方便使用者編寫sql,不用過多關心以上那些類,建立了一個MysqlStatement類,同樣繼承了BaseSqlStatement
package cw.frame.mybatisext.provider.mysql;
import cw.frame.mybatisext.SqlStatement;
import cw.frame.mybatisext.base.BaseSqlStatement;
import cw.frame.mybatisext.base.ResultMap;
import cw.frame.mybatisext.base.SqlWrapper;
import cw.frame.mybatisext.base.TableIndentityProvider;
import cw.frame.mybatisext.base.entity.RelationshipInfo;
import cw.frame.mybatisext.base.entity.TableInfo;
import cw.frame.mybatisext.base.entity.BaseExtEntity;
import cw.frame.mybatisext.enumeration.ConditionType;
import cw.frame.mybatisext.enumeration.JoinType;
import cw.frame.mybatisext.enumeration.OrderType;
import cw.frame.mybatisext.provider.mysql.statement.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class MySqlStatement extends BaseSqlStatement {
private Class<? extends BaseExtEntity> entityClass;
private TableInfo tableInfo;
private TableIndentityProvider tableIndentityProvider;
private OperateType operateType;
private SelectStatement selectStatement = null;
private List<MySqlStatement> selectSubMySqlStatements = null;
private MutiSqlStatement joinStatements = null;
private MutiSqlStatement conditionStatemennts = null;
private MutiSqlStatement orderStatemennts = null;
private MutiSqlStatement groupStatemennts = null;
private MutiSqlStatement havingStatemennts = null;
private String limitString = "";
private List<UpdateSetItem> updateSetItems = new ArrayList<UpdateSetItem>();
public static MySqlStatement createSelectStatement(Class<? extends BaseExtEntity> entityClass){
return new MySqlStatement(entityClass, OperateType.SELECT);
}
public static MySqlStatement createUpdateStatement(Class<? extends BaseExtEntity> entityClass){
return new MySqlStatement(entityClass, OperateType.UPDATE);
}
public static MySqlStatement createDeleteStatement(Class<? extends BaseExtEntity> entityClass){
return new MySqlStatement(entityClass, OperateType.DELETE);
}
public MySqlStatement(Class<? extends BaseExtEntity> entityClass, TableIndentityProvider tableIndentityProvider){
this.init(entityClass, tableIndentityProvider);
this.operateType = OperateType.SELECT;
}
private MySqlStatement(Class<? extends BaseExtEntity> entityClass, OperateType operateType){
this.init(entityClass, new TableIndentityProvider());
this.operateType = operateType;
}
public SelectStatement getSelectStatement() {
return this.selectStatement;
}
public MySqlStatement select(String... propertyNames){
this.selectStatement.select(propertyNames);
return this;
}
public MySqlStatement selectAs(String propertyName, String resultPropertyName){
this.selectStatement.selectAs(propertyName, resultPropertyName);
return this;
}
public MySqlStatement selectAs(Map<String, String> propertyNameMap){
this.selectStatement.selectAs(propertyNameMap);
return this;
}
public MySqlStatement set(String propertyName, Object propertyValue){
this.updateSetItems.add(new UpdateSetItem(propertyName, propertyValue));
return this;
}
/**
* set a.name = b.name
* @param propertyName
* @param subQuery
* @param subPropertyName
* @return
*/
public MySqlStatement set(String propertyName, MySqlStatement subQuery, String subPropertyName){
this.updateSetItems.add(new UpdateSetItem(propertyName, subQuery.getSelectStatement().getAliasTableName(), subPropertyName));
return this;
}
public MySqlStatement set(Map<String, Object> propertyMap){
for (String propertyName : propertyMap.keySet()){
this.updateSetItems.add(new UpdateSetItem(propertyName, propertyMap.get(propertyName)));
}
return this;
}
public MySqlStatement join(Class<? extends BaseExtEntity> classType, JoinType joinType, String fromPropertyName, String toPropertyName){
SingleJoinStatement singleJoinStatement = this.getSingleJoinStatement(classType, joinType);
singleJoinStatement.setRelationship(fromPropertyName, toPropertyName);
return this;
}
public MySqlStatement join(Class<? extends BaseExtEntity> classType, JoinType joinType, Map<String, String> relationshipMap){
SingleJoinStatement singleJoinStatement = this.getSingleJoinStatement(classType, joinType);
for (String fromPropertyName : relationshipMap.keySet()){
singleJoinStatement.setRelationship(fromPropertyName, relationshipMap.get(fromPropertyName));
}
return this;
}
public MySqlStatement join(MySqlStatement subQuery, JoinType joinType, String fromPropertyName, String toPropertyName, boolean joinByQuery, String relationshipPropertyName){
if (joinByQuery){
SingleJoinStatement statement = this.getSingleJoinStatement(subQuery, joinType);
statement.setRelationship(fromPropertyName, toPropertyName);
} else {
SingleJoinStatement singleJoinStatement = this.getSingleJoinStatement(subQuery.getSelectStatement(), joinType);
singleJoinStatement.setRelationship(fromPropertyName, toPropertyName);
}
if (this.selectSubMySqlStatements == null){
this.selectSubMySqlStatements = new ArrayList<MySqlStatement>();
}
this.selectSubMySqlStatements.add(subQuery);
this.getResultMap().addSubResultMap(subQuery.getResultMap(), relationshipPropertyName);
return this;
}
public MySqlStatement join(MySqlStatement subQuery, JoinType joinType, Map<String, String> relationshipMap, boolean joinByQuery){
SingleJoinStatement singleJoinStatement;
if (joinByQuery){
singleJoinStatement = this.getSingleJoinStatement(subQuery, joinType);
} else {
singleJoinStatement = this.getSingleJoinStatement(subQuery.getSelectStatement(), joinType);
}
for (String fromPropertyName : relationshipMap.keySet()){
singleJoinStatement.setRelationship(fromPropertyName, relationshipMap.get(fromPropertyName));
}
return this;
}
public MySqlStatement where(String propertyName, ConditionType conditionType, Object value){
this.setCondition(this.selectStatement, propertyName, conditionType, value);
return this;
}
public MySqlStatement where(MySqlStatement subQuery, String propertyName, ConditionType conditionType, Object value){
this.setCondition(subQuery.getSelectStatement(), propertyName, conditionType, value);
return this;
}
public MySqlStatement orderBy(String propertyName, OrderType orderType){
this.setOrderBy(this.selectStatement, propertyName, orderType);
return this;
}
public MySqlStatement orderBy(MySqlStatement subQuery, String propertyName, OrderType orderType){
this.setOrderBy(subQuery.getSelectStatement(), propertyName, orderType);
return this;
}
public MySqlStatement groupBy(String propertyName){
this.setGroupBy(this.selectStatement, propertyName);
return this;
}
public MySqlStatement groupBy(MySqlStatement subQuery, String propertyName){
this.setGroupBy(subQuery.getSelectStatement(), propertyName);
return this;
}
public MySqlStatement having(String expression, ConditionType conditionType, Object value){
this.setHaving(this.selectStatement, expression, conditionType, value);
return this;
}
public MySqlStatement having(MySqlStatement subQuery, String expression, ConditionType conditionType, Object value){
this.setHaving(subQuery.getSelectStatement(), expression, conditionType, value);
return this;
}
public MySqlStatement limit(int limit){
return this.limit(limit, 0);
}
public MySqlStatement limit(int limit, int skip){
StringBuilder sb = new StringBuilder();
sb.append("limit ");
if (skip > 0){
sb.append(skip).append(",").append(limit);
} else {
sb.append(limit);
}
this.limitString = sb.toString();
return this;
}
/**
* 根據實體型別建立子查詢物件,不會有查詢欄位返回
* @param entityClass
* @return MySqlStatement
*/
public MySqlStatement createSubQuery(Class<? extends BaseExtEntity> entityClass){
MySqlStatement operator = new MySqlStatement(entityClass, this.tableIndentityProvider);
return operator;
}
/**
* 建立子查詢物件,結果儲存於@OneOne or @OneMany定義的關係欄位, 採用inner join連線
* @param relationshipPropertyName 關係欄位名
* @return MySqlStatement
*/
public MySqlStatement createSubQuery(String relationshipPropertyName){
return this.createSubQuery(relationshipPropertyName, JoinType.INNER_JOIN);
}
/**
* 建立子查詢物件,結果儲存於@OneOne or @OneMany定義的關係欄位
* @param relationshipPropertyName 關係欄位名
* @param joinType inner/left/right join
* @return MySqlStatement
*/
public MySqlStatement createSubQuery(String relationshipPropertyName, JoinType joinType){
RelationshipInfo relationshipInfo = this.tableInfo.getOneManyMap().getOrDefault(relationshipPropertyName, null);
if (relationshipInfo == null){
relationshipInfo = this.tableInfo.getOneOneMap().getOrDefault(relationshipPropertyName, null);
}
if (relationshipInfo == null){
throw new IllegalArgumentException("relationshipPropertyName error: " + relationshipPropertyName);
}
MySqlStatement operator = new MySqlStatement(relationshipInfo.getSubTable().getTableEntityClass(), this.tableIndentityProvider);
this.join(operator, joinType, relationshipInfo.getPropertyKey(), relationshipInfo.getForeignKey(), false, relationshipPropertyName);
return operator;
}
@Override
protected void prepare(){
StringBuilder sb = new StringBuilder();
Map<String, Object> parameters = new HashMap<String, Object>();
switch (this.operateType){
case SELECT:
sb.append("select ");
SqlWrapper selectSqlWrapper = this.selectStatement.getSqlWrapper();
sb.append(selectSqlWrapper.getSql());
parameters.putAll(selectSqlWrapper.getParameters());
this.setSubSelectFieldsSql(this.selectSubMySqlStatements, sb, parameters);
sb.append(" from ").append(this.selectStatement.getTableInfo().getTableName()).append(" ");
sb.append(this.selectStatement.getAliasTableName());
this.combineByWrapper(this.joinStatements, sb, parameters, " ");
this.combineByWrapper(this.conditionStatemennts, sb, parameters, " where ");
this.combineByWrapper(this.orderStatemennts, sb, parameters, " order by ");
this.combineByWrapper(this.groupStatemennts, sb, parameters, " group by ");
this.combineByWrapper(this.havingStatemennts, sb, parameters, " having ");
if (this.limitString != null && !this.limitString.isEmpty()){
sb.append(" ").append(this.limitString);
}
break;
case UPDATE:
sb.append("update ").append(this.selectStatement.getTableInfo().getTableName()).append(" ");
sb.append(this.selectStatement.getAliasTableName());
this.combineByWrapper(this.joinStatements, sb, parameters, " ");
sb.append(" set ");
int i=0;
for (UpdateSetItem updateSetItem : this.updateSetItems){
if (i > 0){
sb.append(",");
}
String parameterName = this.getParameterName(this.selectStatement.getAliasTableName(), updateSetItem.getPropertyName());
sb.append(this.selectStatement.getAliasTableName()).append(".`");
sb.append(updateSetItem.getPropertyName());
sb.append("`=");
if (updateSetItem.isUseTargetTableProperty()){
sb.append(updateSetItem.getTargetTableName()).append(".`");
sb.append(updateSetItem.targetPropertyName).append("`");
} else {
sb.append(parameterName);
parameters.put(parameterName, updateSetItem.getPropertyValue());
}
i++;
}
this.combineByWrapper(this.conditionStatemennts, sb, parameters, " where ");
break;
case DELETE:
sb.append("delete ").append(this.selectStatement.getAliasTableName()).append(" from ").append(this.selectStatement.getTableInfo().getTableName()).append(" ");
sb.append(this.selectStatement.getAliasTableName());
this.combineByWrapper(this.joinStatements, sb, parameters, " ");
this.combineByWrapper(this.conditionStatemennts, sb, parameters, " where ");
break;
}
this.setSqlWrapper(sb.toString(), parameters);
}
public List<MySqlStatement> getSelectSubMySqlStatements(){
return this.selectSubMySqlStatements;
}
@Override
public ResultMap getResultMap(){
return this.selectStatement.getResultMap();
}
private void setGroupBy(SelectStatement statement, String propertyName){
String tableName = statement.getAliasTableName();
String columnName = statement.getTableInfo().getColumnByPropertyName(propertyName).getColumnName();
SingleGroupStatement groupStatement = new SingleGroupStatement(columnName, tableName);
if (this.groupStatemennts == null){
this.groupStatemennts = new MutiSqlStatement(",");
}
this.groupStatemennts.addStatement(groupStatement);
}
private void setSubSelectFieldsSql(List<MySqlStatement> subMySqlStatements, StringBuilder sb, Map<String, Object> parameters){
if (subMySqlStatements != null){
for (MySqlStatement operator : subMySqlStatements){
SelectStatement statement = operator.getSelectStatement();
if (statement.hasSelectFields()){
this.combineByWrapper(statement, sb, parameters, ",");
}
this.setSubSelectFieldsSql(operator.getSelectSubMySqlStatements(), sb, parameters);
}
}
}
private void setOrderBy(SelectStatement statement, String propertyName, OrderType orderType){
String tableName = statement.getAliasTableName();
String columnName = statement.getTableInfo().getColumnByPropertyName(propertyName).getColumnName();
SingleOrderStatement singleOrderStatement = new SingleOrderStatement(columnName, orderType, tableName);
if (this.orderStatemennts == null){
this.orderStatemennts = new MutiSqlStatement(",");
}
this.orderStatemennts.addStatement(singleOrderStatement);
}
private void setCondition(SelectStatement statement, String propertyName, ConditionType conditionType, Object value){
if (this.conditionStatemennts == null){
this.conditionStatemennts = new MutiSqlStatement(" and ");
}
String tableName = statement.getAliasTableName();
String columnName = statement.getTableInfo().getColumnByPropertyName(propertyName).getColumnName();
SingleConditionStatement singleConditionStatement = new SingleConditionStatement(tableName, columnName, conditionType, value);
this.conditionStatemennts.addStatement(singleConditionStatement);
}
private SingleJoinStatement getSingleJoinStatement(Class<? extends BaseExtEntity> classType, JoinType joinType){
SelectStatement statement = new SelectStatement(classType, this.tableIndentityProvider.getNextTableAsName());
return this.getSingleJoinStatement(statement, joinType);
}
private SingleJoinStatement getSingleJoinStatement(SelectStatement statement, JoinType joinType){
this.initJoinStatements();
SingleJoinStatement singleJoinStatement = new SingleJoinStatement(this.selectStatement, statement, joinType);
this.joinStatements.addStatement(singleJoinStatement);
return singleJoinStatement;
}
private SingleJoinStatement getSingleJoinStatement(MySqlStatement subQuery, JoinType joinType){
this.initJoinStatements();
SingleJoinStatement singleJoinStatement = new SingleJoinStatement(this.selectStatement, subQuery, joinType);
this.joinStatements.addStatement(singleJoinStatement);
return singleJoinStatement;
}
private void initJoinStatements(){
if (this.joinStatements == null){
this.joinStatements = new MutiSqlStatement(" ");
}
}
private void setHaving(SelectStatement statement, String expression, ConditionType conditionType, Object value){
if (this.havingStatemennts == null){
this.havingStatemennts = new MutiSqlStatement(",");
}
SingleHavingStatement singleHavingStatement = new SingleHavingStatement(statement, expression, conditionType, value);
this.havingStatemennts.addStatement(singleHavingStatement);
}
private void combineByWrapper(SqlStatement statement, StringBuilder sb, Map<String, Object> parameters, String preStr){
if (statement != null){
sb.append(preStr);
SqlWrapper wrapper = statement.getSqlWrapper();
sb.append(wrapper.getSql());
parameters.putAll(wrapper.getParameters());
}
}
private void init(Class<? extends BaseExtEntity> entityClass, TableIndentityProvider tableIndentityProvider){
this.entityClass = entityClass;
this.tableIndentityProvider = tableIndentityProvider;
this.tableInfo = TableInfo.getTableInfo(this.entityClass);
this.selectStatement = new SelectStatement(this.entityClass, this.tableIndentityProvider.getNextTableAsName());
}
private enum OperateType {
SELECT,
UPDATE,
DELETE,
}
private class UpdateSetItem{
private String propertyName;
private Object propertyValue;
private String targetTableName;
private String targetPropertyName;
private boolean useTargetTableProperty;
public UpdateSetItem(String propertyName, Object propertyValue){
this.propertyName = propertyName;
this.propertyValue = propertyValue;
this.useTargetTableProperty = false;
}
public UpdateSetItem(String propertyName, String targetTableName, String targetPropertyName){
this.propertyName = propertyName;
this.targetTableName = targetTableName;
this.targetPropertyName = targetPropertyName;
this.useTargetTableProperty = true;
}
public String getPropertyName() {
return propertyName;
}
public Object getPropertyValue() {
return propertyValue;
}
public String getTargetPropertyName() {
return targetPropertyName;
}
public String getTargetTableName() {
return targetTableName;
}
public boolean isUseTargetTableProperty() {
return useTargetTableProperty;
}
}
}
查詢物件就先介紹到這裡,原始碼下載