/* * The MIT License (MIT) * * Copyright (c) 2014 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package message.mybatis.common.provider; import message.mybatis.common.mapper.EntityHelper; import message.mybatis.common.mapper.MapperHelper; import message.mybatis.common.mapper.MapperTemplate; import org.apache.ibatis.builder.StaticSqlSource; import org.apache.ibatis.jdbc.SQL; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.ParameterMapping; import org.apache.ibatis.scripting.xmltags.IfSqlNode; import org.apache.ibatis.scripting.xmltags.MixedSqlNode; import org.apache.ibatis.scripting.xmltags.SetSqlNode; import org.apache.ibatis.scripting.xmltags.SqlNode; import org.apache.ibatis.scripting.xmltags.StaticTextSqlNode; import org.apache.ibatis.scripting.xmltags.TrimSqlNode; import org.apache.ibatis.scripting.xmltags.VarDeclSqlNode; import org.apache.ibatis.scripting.xmltags.WhereSqlNode; import java.util.LinkedList; import java.util.List; import java.util.Set; /** * Mappper实现类,基础方法实现类.其中的方法与{@code message.mybatis.common.dao.BaseRepository}一一对应 * * @author sunhao(sunhao.java@gmail.com) * @version V1.0, 15/7/13 下午3:39 * @see message.mybatis.common.dao.BaseRepository */ public class MapperProvider extends MapperTemplate { public MapperProvider(Class<?> mapperClass, MapperHelper mapperHelper) { super(mapperClass, mapperHelper); } /** * 根据实体中的id属性进行查询,只能有一个返回值,有多个结果是抛出异常,查询条件使用等号 * * @param ms * @return */ public SqlNode select(MappedStatement ms) { Class<?> entityClass = getSelectReturnType(ms); //修改返回值类型为实体类型 setResultType(ms, entityClass); List<SqlNode> sqlNodes = new LinkedList<SqlNode>(); //静态的sql部分:select column ... from table sqlNodes.add(new StaticTextSqlNode("SELECT " + EntityHelper.getSelectColumns(entityClass) + " FROM " + tableName(entityClass))); //获取全部的主键的列 Set<EntityHelper.EntityColumn> columnList = EntityHelper.getPKColumns(entityClass); List<SqlNode> whereNodes = new LinkedList<SqlNode>(); boolean first = true; //where 主键=#{property} 条件 for (EntityHelper.EntityColumn column : columnList) { whereNodes.add(getColumnEqualsProperty(column, first)); first = false; } sqlNodes.add(new WhereSqlNode(ms.getConfiguration(), new MixedSqlNode(whereNodes))); return new MixedSqlNode(sqlNodes); } /** * 保存一个实体,null的属性不会保存,会使用数据库默认值。 * * @param ms * @return */ public SqlNode inert(MappedStatement ms) { Class<?> entityClass = getSelectReturnType(ms); List<SqlNode> sqlNodes = new LinkedList<SqlNode>(); //insert into table sqlNodes.add(new StaticTextSqlNode("INSERT INTO " + tableName(entityClass))); //获取全部列 Set<EntityHelper.EntityColumn> columnList = EntityHelper.getColumns(entityClass); List<SqlNode> ifNodes = new LinkedList<SqlNode>(); //Identity列只能有一个 Boolean hasIdentityKey = false; //当某个列有主键策略时,不需要考虑他的属性是否为空,因为如果为空,一定会根据主键策略给他生成一个值 for (EntityHelper.EntityColumn column : columnList) { //当使用序列时 if (column.getSequenceName() != null && column.getSequenceName().length() > 0) { //直接将列加进去 ifNodes.add(new StaticTextSqlNode(column.getColumn() + ",")); } else if (column.isIdentity()) { //这种情况下,如果原先的字段有值,需要先缓存起来,否则就一定会使用自动增长 sqlNodes.add(new VarDeclSqlNode(column.getProperty() + "_cache", column.getProperty())); if (hasIdentityKey) { //jdbc类型只需要添加一次 if (column.getGenerator() != null && column.getGenerator().equals("JDBC")) { continue; } throw new RuntimeException(ms.getId() + "对应的实体类" + entityClass.getCanonicalName() + "中包含多个MySql的自动增长列,最多只能有一个!"); } //新增一个selectKey-MS newSelectKeyMappedStatement(ms, column); hasIdentityKey = true; //加入该列 ifNodes.add(new StaticTextSqlNode(column.getColumn() + ",")); } else if (column.isUuid()) { //将UUID的值加入bind节点 sqlNodes.add(new VarDeclSqlNode(column.getProperty() + "_bind", getUUID())); ifNodes.add(new StaticTextSqlNode(column.getColumn() + ",")); } else { ifNodes.add(getIfNotNull(column, new StaticTextSqlNode(column.getColumn() + ","))); } } //将动态的列加入sqlNodes sqlNodes.add(new TrimSqlNode(ms.getConfiguration(), new MixedSqlNode(ifNodes), "(", null, ")", ",")); ifNodes = new LinkedList<SqlNode>(); //处理values(#{property},#{property}...) for (EntityHelper.EntityColumn column : columnList) { //当参数中的属性值不为空的时候,使用传入的值 //自增的情况下,如果默认有值,就会备份到property_cache中 if (column.isIdentity()) { ifNodes.add(new IfSqlNode(new StaticTextSqlNode("#{" + column.getProperty() + "_cache },"), column.getProperty() + "_cache != null ")); } else { ifNodes.add(new IfSqlNode(new StaticTextSqlNode("#{" + column.getProperty() + "},"), column.getProperty() + " != null ")); } if (column.getSequenceName() != null && column.getSequenceName().length() > 0) { ifNodes.add(getIfIsNull(column, new StaticTextSqlNode(getSeqNextVal(column) + " ,"))); } else if (column.isIdentity()) { ifNodes.add(getIfCacheIsNull(column, new StaticTextSqlNode("#{" + column.getProperty() + " },"))); } else if (column.isUuid()) { ifNodes.add(getIfIsNull(column, new StaticTextSqlNode("#{" + column.getProperty() + "_bind },"))); } } //values(#{property},#{property}...) sqlNodes.add(new TrimSqlNode(ms.getConfiguration(), new MixedSqlNode(ifNodes), "VALUES (", null, ")", ",")); return new MixedSqlNode(sqlNodes); } /** * 根据主键更新属性不为null的值。 * * @param ms */ public SqlNode update(MappedStatement ms) { Class<?> entityClass = getSelectReturnType(ms); List<SqlNode> sqlNodes = new LinkedList<SqlNode>(); //update table sqlNodes.add(new StaticTextSqlNode("UPDATE " + tableName(entityClass))); //获取全部列 Set<EntityHelper.EntityColumn> columnList = EntityHelper.getColumns(entityClass); List<SqlNode> ifNodes = new LinkedList<SqlNode>(); //全部的if property!=null and property!='' for (EntityHelper.EntityColumn column : columnList) { if (!column.isId()) { StaticTextSqlNode columnNode = new StaticTextSqlNode(column.getColumn() + " = #{" + column.getProperty() + "}, "); ifNodes.add(getIfNotNull(column, columnNode)); } } sqlNodes.add(new SetSqlNode(ms.getConfiguration(), new MixedSqlNode(ifNodes))); //获取全部的主键的列 columnList = EntityHelper.getPKColumns(entityClass); List<SqlNode> whereNodes = new LinkedList<SqlNode>(); boolean first = true; //where 主键=#{property} 条件 for (EntityHelper.EntityColumn column : columnList) { whereNodes.add(getColumnEqualsProperty(column, first)); first = false; } sqlNodes.add(new WhereSqlNode(ms.getConfiguration(), new MixedSqlNode(whereNodes))); return new MixedSqlNode(sqlNodes); } /** * 根据主键字段进行删除,方法参数必须包含完整的主键属性 * * @param ms */ public void delete(MappedStatement ms) { final Class<?> entityClass = getSelectReturnType(ms); List<ParameterMapping> parameterMappings = getPrimaryKeyParameterMappings(ms); //开始拼sql String sql = new SQL() {{ //delete from table DELETE_FROM(tableName(entityClass)); //where 主键=#{property} 条件 WHERE(EntityHelper.getPrimaryKeyWhere(entityClass)); }}.toString(); //静态SqlSource StaticSqlSource sqlSource = new StaticSqlSource(ms.getConfiguration(), sql, parameterMappings); //替换原有的SqlSource setSqlSource(ms, sqlSource); } }