use of org.sagacity.sqltoy.config.model.TableCascadeModel in project sagacity-sqltoy by chenrenfei.
the class DialectUtils method update.
/**
* @todo 单个对象修改,包含接连修改
* @param sqlToyContext
* @param entity
* @param nullFunction
* @param forceUpdateFields
* @param cascade
* @param generateSqlHandler
* @param forceCascadeClasses
* @param subTableForceUpdateProps
* @param conn
* @param tableName
* @throws Exception
*/
public static Long update(SqlToyContext sqlToyContext, Serializable entity, String nullFunction, String[] forceUpdateFields, final boolean cascade, final GenerateSqlHandler generateSqlHandler, final Class[] forceCascadeClasses, final HashMap<Class, String[]> subTableForceUpdateProps, Connection conn, final Integer dbType, String tableName) throws Exception {
EntityMeta entityMeta = sqlToyContext.getEntityMeta(entity.getClass());
String realTable = entityMeta.getSchemaTable(tableName, dbType);
// 无主键
if (entityMeta.getIdArray() == null) {
throw new IllegalArgumentException("表:" + realTable + " 无主键,不符合update/updateAll规则,请检查表设计是否合理!");
}
// 全部是主键则无需update
if (entityMeta.getRejectIdFieldArray() == null) {
logger.warn("表:" + realTable + " 字段全部是主键不存在更新字段,无需执行更新操作!");
return 0L;
}
Long updateCnt = update(sqlToyContext, entity, entityMeta, nullFunction, forceUpdateFields, conn, dbType, tableName);
// 不存在级联操作
if (!cascade || entityMeta.getCascadeModels().isEmpty()) {
return updateCnt;
}
// 级联保存
HashMap<Type, String> typeMap = new HashMap<Type, String>();
// 即使子对象数据是null,也强制进行级联修改(null表示删除子表数据)
if (forceCascadeClasses != null) {
for (Type type : forceCascadeClasses) {
typeMap.put(type, "");
}
}
// 级联子表数据
List subTableData = null;
String[] forceUpdateProps = null;
EntityMeta subTableEntityMeta;
// 对子表进行级联处理
for (TableCascadeModel cascadeModel : entityMeta.getCascadeModels()) {
final Object[] mainFieldValues = BeanUtil.reflectBeanToAry(entity, cascadeModel.getFields());
subTableEntityMeta = sqlToyContext.getEntityMeta(cascadeModel.getMappedType());
forceUpdateProps = (subTableForceUpdateProps == null) ? null : subTableForceUpdateProps.get(cascadeModel.getMappedType());
// oneToMany
if (cascadeModel.getCascadeType() == 1) {
subTableData = (List) BeanUtil.getProperty(entity, cascadeModel.getProperty());
} else {
subTableData = new ArrayList();
Object item = BeanUtil.getProperty(entity, cascadeModel.getProperty());
if (item != null) {
subTableData.add(item);
}
}
final String[] mappedFields = cascadeModel.getMappedFields();
// 针对子表存量数据,调用级联修改的语句,分delete 和update两种操作 1、删除存量数据;2、设置存量数据状态为停用
if (cascadeModel.getCascadeUpdateSql() != null && ((subTableData != null && !subTableData.isEmpty()) || typeMap.containsKey(cascadeModel.getMappedType()))) {
SqlExecuteStat.debug("执行子表级联更新前的存量数据更新", null);
// 根据quickvo配置文件针对cascade中update-cascade配置组织具体操作sql
SqlToyResult sqlToyResult = SqlConfigParseUtils.processSql(cascadeModel.getCascadeUpdateSql(), mappedFields, mainFieldValues, null);
SqlUtil.executeSql(sqlToyContext.getTypeHandler(), sqlToyResult.getSql(), sqlToyResult.getParamsValue(), null, conn, dbType, null, true);
}
// 子表数据不为空,采取saveOrUpdateAll操作
if (subTableData != null && !subTableData.isEmpty()) {
logger.info("执行update主表:{} 对应级联子表: {} 更新操作!", realTable, subTableEntityMeta.getTableName());
SqlExecuteStat.debug("执行子表级联更新操作", null);
// 将外键值通过反调赋到相关属性上
ReflectPropsHandler reflectPropsHandler = new ReflectPropsHandler() {
public void process() {
for (int i = 0; i < mappedFields.length; i++) {
this.setValue(mappedFields[i], mainFieldValues[i]);
}
}
};
// 这里需要进行修改,mysql\postgresql\sqlite 等存在缺陷(字段值不为null时会报错)
if (dbType == DBType.MYSQL || dbType == DBType.MYSQL57 || dbType == DBType.TIDB) {
mysqlSaveOrUpdateAll(sqlToyContext, subTableEntityMeta, subTableData, reflectPropsHandler, forceUpdateProps, conn, dbType);
} else if (dbType == DBType.POSTGRESQL || dbType == DBType.GAUSSDB) {
postgreSaveOrUpdateAll(sqlToyContext, subTableEntityMeta, subTableData, reflectPropsHandler, forceUpdateProps, conn, dbType);
} else if (dbType == DBType.OCEANBASE) {
oceanBaseSaveOrUpdateAll(sqlToyContext, subTableEntityMeta, subTableData, reflectPropsHandler, forceUpdateProps, conn, dbType);
} else if (dbType == DBType.SQLITE) {
sqliteSaveOrUpdateAll(sqlToyContext, subTableEntityMeta, subTableData, reflectPropsHandler, forceUpdateProps, conn, dbType);
} else // 达梦数据库
if (dbType == DBType.DM) {
dmSaveOrUpdateAll(sqlToyContext, subTableEntityMeta, subTableData, reflectPropsHandler, forceUpdateProps, conn, dbType);
} else // kingbase
if (dbType == DBType.KINGBASE) {
kingbaseSaveOrUpdateAll(sqlToyContext, subTableEntityMeta, subTableData, reflectPropsHandler, forceUpdateProps, conn, dbType);
} else // db2/oracle/mssql 通过merge 方式
{
saveOrUpdateAll(sqlToyContext, subTableData, sqlToyContext.getBatchSize(), subTableEntityMeta, forceUpdateProps, generateSqlHandler, // 设置关联外键字段的属性值(来自主表的主键)
reflectPropsHandler, conn, dbType, null);
}
} else {
logger.info("未执行update主表:{} 对应级联子表: {} 更新操作,子表数据为空!", realTable, subTableEntityMeta.getTableName());
}
}
return updateCnt;
}
use of org.sagacity.sqltoy.config.model.TableCascadeModel in project sagacity-sqltoy by chenrenfei.
the class DialectUtils method loadAll.
/**
* @todo 提供统一的loadAll处理机制
* @param sqlToyContext
* @param entities
* @param cascadeTypes
* @param lockMode
* @param conn
* @param dbType
* @param tableName
* @param lockSqlHandler
* @param fetchSize
* @param maxRows
* @return
* @throws Exception
*/
public static List<?> loadAll(final SqlToyContext sqlToyContext, List<?> entities, List<Class> cascadeTypes, LockMode lockMode, Connection conn, final Integer dbType, String tableName, LockSqlHandler lockSqlHandler, final int fetchSize, final int maxRows) throws Exception {
if (entities == null || entities.isEmpty()) {
return entities;
}
Class entityClass = BeanUtil.getEntityClass(entities.get(0).getClass());
EntityMeta entityMeta = sqlToyContext.getEntityMeta(entityClass);
// 没有主键不能进行load相关的查询
if (null == entityMeta.getIdArray() || entityMeta.getIdArray().length < 1) {
throw new IllegalArgumentException(entityClass.getName() + " Entity Object hasn't primary key,cann't use loadAll method!");
}
DecryptHandler decryptHandler = null;
if (entityMeta.getSecureColumns() != null) {
decryptHandler = new DecryptHandler(sqlToyContext.getFieldsSecureProvider(), entityMeta.getSecureColumns());
}
int idSize = entityMeta.getIdArray().length;
SqlToyResult sqlToyResult = null;
// 单主键
if (idSize == 1) {
// 切取id数组
Object[] idValues = BeanUtil.sliceToArray(entities, entityMeta.getIdArray()[0]);
if (idValues == null || idValues.length == 0) {
throw new IllegalArgumentException(tableName + " loadAll method must assign value for pk field:" + entityMeta.getIdArray()[0]);
}
// 组织loadAll sql语句
String sql = wrapLoadAll(entityMeta, idValues.length, tableName, lockSqlHandler, lockMode, dbType);
sqlToyResult = SqlConfigParseUtils.processSql(sql, null, new Object[] { idValues }, null);
} else // 复合主键
{
List<Object[]> idValues = BeanUtil.reflectBeansToInnerAry(entities, entityMeta.getIdArray(), null, null);
Object[] rowData;
Object cellValue;
// 将条件构造成一个数组
Object[] realValues = new Object[idValues.size() * idSize];
int index = 0;
for (int i = 0, n = idValues.size(); i < n; i++) {
rowData = idValues.get(i);
for (int j = 0; j < idSize; j++) {
cellValue = rowData[j];
// 验证主键值是否合法
if (StringUtil.isBlank(cellValue)) {
throw new IllegalArgumentException(tableName + " loadAll method must assign value for pk,row:" + i + " pk field:" + entityMeta.getIdArray()[j]);
}
realValues[index] = cellValue;
index++;
}
}
// 组织loadAll sql语句
String sql = wrapLoadAll(entityMeta, idValues.size(), tableName, lockSqlHandler, lockMode, dbType);
sqlToyResult = SqlConfigParseUtils.processSql(sql, null, realValues, null);
}
SqlExecuteStat.showSql("执行依据主键批量查询", sqlToyResult.getSql(), sqlToyResult.getParamsValue());
List<?> entitySet = SqlUtil.findByJdbcQuery(sqlToyContext.getTypeHandler(), sqlToyResult.getSql(), sqlToyResult.getParamsValue(), entityClass, null, decryptHandler, conn, dbType, false, entityMeta.getColumnFieldMap(), fetchSize, maxRows);
// 处理类中的@Translate注解,进行缓存翻译
ResultUtils.wrapResultTranslate(sqlToyContext, entitySet, entityClass);
if (entitySet == null || entitySet.isEmpty()) {
return entitySet;
}
// 存在主表对应子表
if (null != cascadeTypes && !cascadeTypes.isEmpty() && !entityMeta.getCascadeModels().isEmpty()) {
StringBuilder subTableSql = new StringBuilder();
List items;
SqlToyResult subToyResult;
EntityMeta mappedMeta;
int fieldSize;
List<Object[]> idValues = null;
String colName;
Object[] rowData;
Object cellValue;
for (TableCascadeModel cascadeModel : entityMeta.getCascadeModels()) {
if (cascadeTypes.contains(cascadeModel.getMappedType())) {
mappedMeta = sqlToyContext.getEntityMeta(cascadeModel.getMappedType());
// 清空buffer
subTableSql.delete(0, subTableSql.length());
// 构造查询语句,update 2019-12-09 使用完整字段
subTableSql.append(ReservedWordsUtil.convertSimpleSql(mappedMeta.getLoadAllSql(), dbType)).append(" where ");
String orderCols = "";
boolean hasOrder = StringUtil.isNotBlank(cascadeModel.getOrderBy());
boolean hasExtCondtion = StringUtil.isNotBlank(cascadeModel.getLoadExtCondition()) ? true : false;
fieldSize = cascadeModel.getMappedFields().length;
// 单主键
if (fieldSize == 1) {
colName = cascadeModel.getMappedColumns()[0];
colName = ReservedWordsUtil.convertWord(colName, dbType);
subTableSql.append(colName);
subTableSql.append(" in (?) ");
if (hasOrder) {
orderCols = orderCols.concat(colName).concat(",");
}
} else // 复合主键
{
// 构造(field1=? and field2=?)
String condition = " (";
for (int i = 0; i < fieldSize; i++) {
colName = cascadeModel.getMappedColumns()[i];
colName = ReservedWordsUtil.convertWord(colName, dbType);
if (i > 0) {
condition = condition.concat(" and ");
}
condition = condition.concat(colName).concat("=?");
if (hasOrder) {
orderCols = orderCols.concat(colName).concat(",");
}
}
condition = condition.concat(") ");
// 构造成 (field1=? and field2=?) or (field1=? and field2=?)
if (hasExtCondtion) {
subTableSql.append(" (");
}
idValues = BeanUtil.reflectBeansToInnerAry(entitySet, cascadeModel.getFields(), null, null);
for (int i = 0; i < idValues.size(); i++) {
if (i > 0) {
subTableSql.append(" or ");
}
subTableSql.append(condition);
}
if (hasExtCondtion) {
subTableSql.append(") ");
}
}
// 自定义扩展条件
if (hasExtCondtion) {
subTableSql.append(" and ").append(cascadeModel.getLoadExtCondition());
}
if (hasOrder) {
subTableSql.append(" order by ").append(orderCols).append(cascadeModel.getOrderBy());
}
// 单主键
if (fieldSize == 1) {
Object[] pkValues = BeanUtil.sliceToArray(entitySet, cascadeModel.getFields()[0]);
subToyResult = SqlConfigParseUtils.processSql(subTableSql.toString(), null, new Object[] { pkValues }, null);
} else {
// 复合主键,将条件值构造成一个数组
Object[] realValues = new Object[idValues.size() * fieldSize];
int index = 0;
for (int i = 0, n = idValues.size(); i < n; i++) {
rowData = idValues.get(i);
for (int j = 0; j < fieldSize; j++) {
cellValue = rowData[j];
realValues[index] = cellValue;
index++;
}
}
subToyResult = SqlConfigParseUtils.processSql(subTableSql.toString(), null, realValues, null);
}
SqlExecuteStat.showSql("执行级联加载子表", subToyResult.getSql(), subToyResult.getParamsValue());
// 加密字段解密
DecryptHandler subDecryptHandler = null;
if (mappedMeta.getSecureColumns() != null) {
subDecryptHandler = new DecryptHandler(sqlToyContext.getFieldsSecureProvider(), mappedMeta.getSecureColumns());
}
items = SqlUtil.findByJdbcQuery(sqlToyContext.getTypeHandler(), subToyResult.getSql(), subToyResult.getParamsValue(), cascadeModel.getMappedType(), null, subDecryptHandler, conn, dbType, false, mappedMeta.getColumnFieldMap(), SqlToyConstants.FETCH_SIZE, maxRows);
// 处理子类中的@Translate注解,进行缓存翻译
ResultUtils.wrapResultTranslate(sqlToyContext, items, cascadeModel.getMappedType());
SqlExecuteStat.debug("子表加载结果", "子记录数:{} 条", items.size());
// 将item的值分配映射到main主表对象上
BeanUtil.loadAllMapping(entitySet, items, cascadeModel);
}
}
}
return entitySet;
}
use of org.sagacity.sqltoy.config.model.TableCascadeModel in project sagacity-sqltoy by chenrenfei.
the class DialectUtils method deleteAll.
/**
* @todo 批量删除对象并级联删除掉子表数据
* @param sqlToyContext
* @param entities
* @param batchSize
* @param conn
* @param dbType
* @param autoCommit
* @param tableName
* @return
* @throws Exception
*/
public static Long deleteAll(SqlToyContext sqlToyContext, List<?> entities, final int batchSize, Connection conn, final Integer dbType, final Boolean autoCommit, final String tableName) throws Exception {
if (null == entities || entities.isEmpty()) {
return 0L;
}
EntityMeta entityMeta = sqlToyContext.getEntityMeta(entities.get(0).getClass());
// 记录数量小于1000且无级联采用一次sql执行完成删除
// if (entities.size() < 1000 && entityMeta.getCascadeModels().isEmpty()) {
// }
String realTable = entityMeta.getSchemaTable(tableName, dbType);
if (null == entityMeta.getIdArray()) {
throw new IllegalArgumentException("delete/deleteAll 操作,表:" + realTable + " 没有主键,请检查表设计!");
}
List<Object[]> idValues = BeanUtil.reflectBeansToInnerAry(entities, entityMeta.getIdArray(), null, null);
// 判断主键值是否存在空
Object[] idsValue;
for (int i = 0, n = idValues.size(); i < n; i++) {
idsValue = idValues.get(i);
for (Object obj : idsValue) {
if (StringUtil.isBlank(obj)) {
throw new IllegalArgumentException("第[" + i + "]行数据主键值存在空,批量删除以主键为依据,表:" + realTable + " 主键不能为空!");
}
}
}
int idsLength = entityMeta.getIdArray().length;
Integer[] parameterTypes = new Integer[idsLength];
for (int i = 0, n = idsLength; i < n; i++) {
parameterTypes[i] = entityMeta.getColumnJdbcType(entityMeta.getIdArray()[i]);
}
// 级联批量删除子表数据
if (!entityMeta.getCascadeModels().isEmpty()) {
EntityMeta subTableMeta;
String delSubTableSql;
int mapFieldSize;
int meter = 0;
for (TableCascadeModel cascadeModel : entityMeta.getCascadeModels()) {
// 如果数据库本身通过on delete cascade机制,则sqltoy无需进行删除操作
if (cascadeModel.isDelete()) {
subTableMeta = sqlToyContext.getEntityMeta(cascadeModel.getMappedType());
List<Object[]> mainFieldValues = BeanUtil.reflectBeansToInnerAry(entities, cascadeModel.getFields(), null, null);
mapFieldSize = cascadeModel.getFields().length;
meter = 0;
for (Object[] row : mainFieldValues) {
for (int i = 0; i < mapFieldSize; i++) {
if (row[i] == null) {
throw new IllegalArgumentException("第:" + meter + "行,表:" + realTable + " 级联删除子表:" + subTableMeta.getTableName() + " 对应属性:" + cascadeModel.getFields()[i] + " 值为null!");
}
}
meter++;
}
Integer[] subTableFieldType = new Integer[mapFieldSize];
for (int i = 0, n = mapFieldSize; i < n; i++) {
subTableFieldType[i] = subTableMeta.getColumnJdbcType(cascadeModel.getMappedFields()[i]);
}
delSubTableSql = ReservedWordsUtil.convertSql(cascadeModel.getDeleteSubTableSql(), dbType);
SqlExecuteStat.showSql("级联删除子表记录", delSubTableSql, null);
SqlUtilsExt.batchUpdateByJdbc(sqlToyContext.getTypeHandler(), delSubTableSql, mainFieldValues, subTableFieldType, null, null, sqlToyContext.getBatchSize(), null, conn, dbType);
}
}
}
String deleteSql = ReservedWordsUtil.convertSql("delete from ".concat(realTable).concat(" ").concat(entityMeta.getIdArgWhereSql()), dbType);
SqlExecuteStat.showSql("批量删除[" + idValues.size() + "]条记录", deleteSql, null);
return SqlUtilsExt.batchUpdateByJdbc(sqlToyContext.getTypeHandler(), deleteSql, idValues, parameterTypes, null, null, batchSize, autoCommit, conn, dbType);
}
use of org.sagacity.sqltoy.config.model.TableCascadeModel in project sagacity-sqltoy by chenrenfei.
the class SqlServerDialectUtils method update.
/**
* @todo 单个对象修改,包含级联修改
* @param sqlToyContext
* @param entity
* @param forceUpdateFields
* @param cascade
* @param emptyCascadeClasses
* @param subTableForceUpdateProps
* @param conn
* @param dbType
* @param tableName
* @return
* @throws Exception
*/
public static Long update(SqlToyContext sqlToyContext, Serializable entity, String[] forceUpdateFields, final boolean cascade, final Class[] emptyCascadeClasses, final HashMap<Class, String[]> subTableForceUpdateProps, Connection conn, final Integer dbType, final String tableName) throws Exception {
EntityMeta entityMeta = sqlToyContext.getEntityMeta(entity.getClass());
String realTable = entityMeta.getSchemaTable(tableName, dbType);
Long updateCount = DialectUtils.update(sqlToyContext, entity, entityMeta, "isnull", forceUpdateFields, conn, dbType, realTable);
// 级联修改
if (cascade && !entityMeta.getCascadeModels().isEmpty()) {
HashMap<Type, String> typeMap = new HashMap<Type, String>();
if (emptyCascadeClasses != null) {
for (Type type : emptyCascadeClasses) {
typeMap.put(type, "");
}
}
// 级联子表数据
List subTableData = null;
String[] forceUpdateProps = null;
EntityMeta subTableEntityMeta;
for (TableCascadeModel cascadeModel : entityMeta.getCascadeModels()) {
final Object[] mainFieldValues = BeanUtil.reflectBeanToAry(entity, cascadeModel.getFields());
subTableEntityMeta = sqlToyContext.getEntityMeta(cascadeModel.getMappedType());
forceUpdateProps = (subTableForceUpdateProps == null) ? null : subTableForceUpdateProps.get(cascadeModel.getMappedType());
if (cascadeModel.getCascadeType() == 1) {
subTableData = (List) BeanUtil.getProperty(entity, cascadeModel.getProperty());
} else {
subTableData = new ArrayList();
Object item = BeanUtil.getProperty(entity, cascadeModel.getProperty());
if (item != null) {
subTableData.add(item);
}
}
final String[] mappedFields = cascadeModel.getMappedFields();
// 针对存量子表数据,调用级联修改的语句,分delete 和update两种操作 1、删除存量数据;2、设置存量数据状态为停用
if (cascadeModel.getCascadeUpdateSql() != null && ((subTableData != null && !subTableData.isEmpty()) || typeMap.containsKey(cascadeModel.getMappedType()))) {
SqlExecuteStat.debug("执行子表级联更新前的存量数据更新", null);
SqlToyResult sqlToyResult = SqlConfigParseUtils.processSql(cascadeModel.getCascadeUpdateSql(), mappedFields, mainFieldValues, null);
SqlUtil.executeSql(sqlToyContext.getTypeHandler(), sqlToyResult.getSql(), sqlToyResult.getParamsValue(), null, conn, dbType, null, true);
}
// 子表数据不为空,采取saveOrUpdateAll操作
if (subTableData != null && !subTableData.isEmpty()) {
logger.info("执行update主表:{} 对应级联子表: {} 更新操作!", tableName, subTableEntityMeta.getTableName());
SqlExecuteStat.debug("执行子表级联更新操作", null);
saveOrUpdateAll(sqlToyContext, subTableData, sqlToyContext.getBatchSize(), // 设置关联外键字段的属性值(来自主表的主键)
new ReflectPropsHandler() {
public void process() {
for (int i = 0; i < mappedFields.length; i++) {
this.setValue(mappedFields[i], mainFieldValues[i]);
}
}
}, forceUpdateProps, conn, dbType, null, null);
} else {
logger.info("未执行update主表:{} 对应级联子表: {} 更新操作,子表数据为空!", tableName, subTableEntityMeta.getTableName());
}
}
}
return updateCount;
}
use of org.sagacity.sqltoy.config.model.TableCascadeModel in project sagacity-sqltoy by chenrenfei.
the class BeanUtil method getCascadeModels.
/**
* @TODO 获取类的级联关系
* @param entityClass
* @return
*/
public static List<TableCascadeModel> getCascadeModels(Class entityClass) {
String className = entityClass.getName();
List<TableCascadeModel> result = cascadeModels.get(className);
if (result == null) {
result = new ArrayList<TableCascadeModel>();
Field[] cascadeFields = parseCascadeFields(entityClass);
for (Field field : cascadeFields) {
TableCascadeModel cascadeModel = new TableCascadeModel();
cascadeModel.setProperty(field.getName());
cascadeModel.setMappedType((Class) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0]);
OneToMany oneToMany = field.getAnnotation(OneToMany.class);
OneToOne oneToOne = field.getAnnotation(OneToOne.class);
if (oneToMany != null) {
cascadeModel.setCascadeType(1);
cascadeModel.setFields(oneToMany.fields());
cascadeModel.setMappedFields(oneToMany.mappedFields());
} else {
cascadeModel.setCascadeType(2);
cascadeModel.setFields(oneToOne.fields());
cascadeModel.setMappedFields(oneToOne.mappedFields());
}
result.add(cascadeModel);
}
cascadeModels.put(className, result);
}
return result;
}
Aggregations