001/* 002 * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package com.mybatisflex.core.provider; 017 018import com.mybatisflex.core.FlexConsts; 019import com.mybatisflex.core.dialect.DialectFactory; 020import com.mybatisflex.core.exception.FlexAssert; 021import com.mybatisflex.core.query.CPI; 022import com.mybatisflex.core.query.QueryTable; 023import com.mybatisflex.core.query.QueryWrapper; 024import com.mybatisflex.core.table.TableInfo; 025import com.mybatisflex.core.table.TableInfoFactory; 026import com.mybatisflex.core.util.ArrayUtil; 027import com.mybatisflex.core.util.CollectionUtil; 028import com.mybatisflex.core.util.StringUtil; 029import org.apache.ibatis.builder.annotation.ProviderContext; 030 031import java.io.Serializable; 032import java.util.*; 033 034@SuppressWarnings({"rawtypes", "DuplicatedCode"}) 035public class EntitySqlProvider { 036 037 /** 038 * 不让实例化,使用静态方法的模式,效率更高,非静态方法每次都会实例化当前类 039 * 参考源码: {{@link org.apache.ibatis.builder.annotation.ProviderSqlSource#getBoundSql(Object)} 040 */ 041 private EntitySqlProvider() { 042 } 043 044 /** 045 * insert 的 SQL 构建。 046 * 047 * @param params 方法参数 048 * @param context 上下文对象 049 * @return SQL 语句 050 * @see com.mybatisflex.core.BaseMapper#insert(Object) 051 */ 052 public static String insert(Map params, ProviderContext context) { 053 Object entity = ProviderUtil.getEntity(params); 054 055 FlexAssert.notNull(entity, "entity"); 056 057 boolean ignoreNulls = ProviderUtil.isIgnoreNulls(params); 058 059 TableInfo tableInfo = ProviderUtil.getTableInfo(context); 060 061 //设置乐观锁版本字段的初始化数据 062 tableInfo.initVersionValueIfNecessary(entity); 063 064 //设置租户ID 065 tableInfo.initTenantIdIfNecessary(entity); 066 067 //设置逻辑删除字段的出初始化数据 068 tableInfo.initLogicDeleteValueIfNecessary(entity); 069 070 //执行 onInsert 监听器 071 tableInfo.invokeOnInsertListener(entity); 072 073 Object[] values = tableInfo.buildInsertSqlArgs(entity, ignoreNulls); 074 ProviderUtil.setSqlArgs(params, values); 075 076 return DialectFactory.getDialect().forInsertEntity(tableInfo, entity, ignoreNulls); 077 } 078 079 080 /** 081 * insertWithPk 的 SQL 构建。 082 * 083 * @param params 方法参数 084 * @param context 上下文对象 085 * @return SQL 语句 086 * @see com.mybatisflex.core.BaseMapper#insertWithPk(Object, boolean) 087 */ 088 public static String insertWithPk(Map params, ProviderContext context) { 089 Object entity = ProviderUtil.getEntity(params); 090 091 FlexAssert.notNull(entity, "entity"); 092 093 boolean ignoreNulls = ProviderUtil.isIgnoreNulls(params); 094 095 TableInfo tableInfo = ProviderUtil.getTableInfo(context); 096 097 //设置乐观锁版本字段的初始化数据 098 tableInfo.initVersionValueIfNecessary(entity); 099 100 //设置租户ID 101 tableInfo.initTenantIdIfNecessary(entity); 102 103 //设置逻辑删除字段的出初始化数据 104 tableInfo.initLogicDeleteValueIfNecessary(entity); 105 106 //执行 onInsert 监听器 107 tableInfo.invokeOnInsertListener(entity); 108 109 Object[] values = tableInfo.buildInsertSqlArgsWithPk(entity, ignoreNulls); 110 ProviderUtil.setSqlArgs(params, values); 111 112 return DialectFactory.getDialect().forInsertEntityWithPk(tableInfo, entity, ignoreNulls); 113 } 114 115 116 /** 117 * insertBatch 的 SQL 构建。 118 * 119 * @param params 方法参数 120 * @param context 上下文对象 121 * @return SQL 语句 122 * @see com.mybatisflex.core.BaseMapper#insertBatch(List) 123 * @see com.mybatisflex.core.FlexConsts#METHOD_INSERT_BATCH 124 */ 125 public static String insertBatch(Map params, ProviderContext context) { 126 List<Object> entities = ProviderUtil.getEntities(params); 127 128 FlexAssert.notEmpty(entities, "entities"); 129 130 TableInfo tableInfo = ProviderUtil.getTableInfo(context); 131 for (Object entity : entities) { 132 tableInfo.initVersionValueIfNecessary(entity); 133 tableInfo.initTenantIdIfNecessary(entity); 134 tableInfo.initLogicDeleteValueIfNecessary(entity); 135 136 //执行 onInsert 监听器 137 tableInfo.invokeOnInsertListener(entity); 138 } 139 140 141 Object[] allValues = FlexConsts.EMPTY_ARRAY; 142 for (Object entity : entities) { 143 allValues = ArrayUtil.concat(allValues, tableInfo.buildInsertSqlArgs(entity, false)); 144 } 145 146 ProviderUtil.setSqlArgs(params, allValues); 147 148 return DialectFactory.getDialect().forInsertEntityBatch(tableInfo, entities); 149 } 150 151 152 /** 153 * deleteById 的 SQL 构建。 154 * 155 * @param params 方法参数 156 * @param context 上下文对象 157 * @return SQL 语句 158 * @see com.mybatisflex.core.BaseMapper#deleteById(Serializable) 159 */ 160 public static String deleteById(Map params, ProviderContext context) { 161 Object[] primaryValues = ProviderUtil.getPrimaryValues(params); 162 163 FlexAssert.notEmpty(primaryValues, "primaryValues"); 164 165 TableInfo tableInfo = ProviderUtil.getTableInfo(context); 166 167 Object[] allValues = ArrayUtil.concat(primaryValues, tableInfo.buildTenantIdArgs()); 168 ProviderUtil.setSqlArgs(params, allValues); 169 170 return DialectFactory.getDialect().forDeleteEntityById(tableInfo); 171 } 172 173 174 /** 175 * deleteBatchByIds 的 SQL 构建。 176 * 177 * @param params 方法参数 178 * @param context 上下文对象 179 * @return SQL 语句 180 * @see com.mybatisflex.core.BaseMapper#deleteBatchByIds(Collection) 181 */ 182 public static String deleteBatchByIds(Map params, ProviderContext context) { 183 Object[] primaryValues = ProviderUtil.getPrimaryValues(params); 184 185 FlexAssert.notEmpty(primaryValues, "primaryValues"); 186 187 TableInfo tableInfo = ProviderUtil.getTableInfo(context); 188 189 Object[] tenantIdArgs = tableInfo.buildTenantIdArgs(); 190 ProviderUtil.setSqlArgs(params, ArrayUtil.concat(primaryValues, tenantIdArgs)); 191 192 return DialectFactory.getDialect().forDeleteEntityBatchByIds(tableInfo, primaryValues); 193 } 194 195 196 /** 197 * deleteByQuery 的 SQL 构建。 198 * 199 * @param params 方法参数 200 * @param context 上下文对象 201 * @return SQL 语句 202 * @see com.mybatisflex.core.BaseMapper#deleteByQuery(QueryWrapper) 203 */ 204 public static String deleteByQuery(Map params, ProviderContext context) { 205 QueryWrapper queryWrapper = ProviderUtil.getQueryWrapper(params); 206 207 TableInfo tableInfo = ProviderUtil.getTableInfo(context); 208 CPI.setFromIfNecessary(queryWrapper, tableInfo.getSchema(), tableInfo.getTableName()); 209 210 tableInfo.appendConditions(null, queryWrapper); 211 212 String sql = DialectFactory.getDialect().forDeleteEntityBatchByQuery(tableInfo, queryWrapper); 213 ProviderUtil.setSqlArgs(params, CPI.getValueArray(queryWrapper)); 214 return sql; 215 } 216 217 218 /** 219 * update 的 SQL 构建。 220 * 221 * @param params 方法参数 222 * @param context 上下文对象 223 * @return SQL 语句 224 * @see com.mybatisflex.core.BaseMapper#update(Object, boolean) 225 */ 226 public static String update(Map params, ProviderContext context) { 227 Object entity = ProviderUtil.getEntity(params); 228 229 FlexAssert.notNull(entity, "entity can not be null for execute update"); 230 231 boolean ignoreNulls = ProviderUtil.isIgnoreNulls(params); 232 233 TableInfo tableInfo = ProviderUtil.getTableInfo(context); 234 235 //执行 onUpdate 监听器 236 tableInfo.invokeOnUpdateListener(entity); 237 238 Object[] updateValues = tableInfo.buildUpdateSqlArgs(entity, ignoreNulls, false); 239 Object[] primaryValues = tableInfo.buildPkSqlArgs(entity); 240 Object[] tenantIdArgs = tableInfo.buildTenantIdArgs(); 241 242 FlexAssert.assertAreNotNull(primaryValues, "The value of primary key must not be null for execute update an entity, entity[%s]", entity); 243 244 ProviderUtil.setSqlArgs(params, ArrayUtil.concat(updateValues, primaryValues, tenantIdArgs)); 245 246 return DialectFactory.getDialect().forUpdateEntity(tableInfo, entity, ignoreNulls); 247 } 248 249 250 /** 251 * updateByQuery 的 SQL 构建。 252 * 253 * @param params 方法参数 254 * @param context 上下文对象 255 * @return SQL 语句 256 * @see com.mybatisflex.core.BaseMapper#updateByQuery(Object, boolean, QueryWrapper) 257 */ 258 public static String updateByQuery(Map params, ProviderContext context) { 259 Object entity = ProviderUtil.getEntity(params); 260 261 FlexAssert.notNull(entity, "entity can not be null"); 262 263 boolean ignoreNulls = ProviderUtil.isIgnoreNulls(params); 264 265 QueryWrapper queryWrapper = ProviderUtil.getQueryWrapper(params); 266 appendTableConditions(context,queryWrapper,false); 267 268 TableInfo tableInfo = ProviderUtil.getTableInfo(context); 269 270 //执行 onUpdate 监听器 271 tableInfo.invokeOnUpdateListener(entity); 272 273 //处理逻辑删除 和 多租户等 274 tableInfo.appendConditions(entity, queryWrapper); 275 276 //优先构建 sql,再构建参数 277 String sql = DialectFactory.getDialect().forUpdateEntityByQuery(tableInfo, entity, ignoreNulls, queryWrapper); 278 279 Object[] joinValueArray = CPI.getJoinValueArray(queryWrapper); 280 Object[] values = tableInfo.buildUpdateSqlArgs(entity, ignoreNulls, true); 281 Object[] queryParams = CPI.getConditionValueArray(queryWrapper); 282 283 Object[] paramValues = ArrayUtil.concat(joinValueArray,ArrayUtil.concat(values,queryParams)); 284 285 ProviderUtil.setSqlArgs(params, paramValues); 286 287 return sql; 288 } 289 290 291 292 /** 293 * selectOneById 的 SQL 构建。 294 * 295 * @param params 方法参数 296 * @param context 上下文对象 297 * @return SQL 语句 298 * @see com.mybatisflex.core.BaseMapper#selectOneById(Serializable) 299 */ 300 public static String selectOneById(Map params, ProviderContext context) { 301 Object[] primaryValues = ProviderUtil.getPrimaryValues(params); 302 303 FlexAssert.notEmpty(primaryValues, "primaryValues"); 304 305 TableInfo tableInfo = ProviderUtil.getTableInfo(context); 306 307 Object[] allValues = ArrayUtil.concat(primaryValues, tableInfo.buildTenantIdArgs()); 308 309 ProviderUtil.setSqlArgs(params, allValues); 310 311 return DialectFactory.getDialect().forSelectOneEntityById(tableInfo); 312 } 313 314 315 /** 316 * selectListByIds 的 SQL 构建。 317 * 318 * @param params 方法参数 319 * @param context 上下文对象 320 * @return SQL 语句 321 * @see com.mybatisflex.core.BaseMapper#selectListByIds(Collection) 322 */ 323 public static String selectListByIds(Map params, ProviderContext context) { 324 Object[] primaryValues = ProviderUtil.getPrimaryValues(params); 325 326 FlexAssert.notEmpty(primaryValues, "primaryValues"); 327 328 TableInfo tableInfo = ProviderUtil.getTableInfo(context); 329 330 Object[] allValues = ArrayUtil.concat(primaryValues, tableInfo.buildTenantIdArgs()); 331 ProviderUtil.setSqlArgs(params, allValues); 332 333 return DialectFactory.getDialect().forSelectEntityListByIds(tableInfo, primaryValues); 334 } 335 336 337 /** 338 * selectListByQuery 的 SQL 构建。 339 * 340 * @param params 方法参数 341 * @param context 上下文对象 342 * @return SQL 语句 343 * @see com.mybatisflex.core.BaseMapper#selectListByQuery(QueryWrapper) 344 */ 345 public static String selectListByQuery(Map params, ProviderContext context) { 346 QueryWrapper queryWrapper = ProviderUtil.getQueryWrapper(params); 347 348 appendTableConditions(context, queryWrapper, true); 349 350 //优先构建 sql,再构建参数 351 String sql = DialectFactory.getDialect().forSelectByQuery(queryWrapper); 352 353 Object[] values = CPI.getValueArray(queryWrapper); 354 ProviderUtil.setSqlArgs(params, values); 355 356 return sql; 357 } 358 359 360 /** 361 * selectCountByQuery 的 SQL 构建。 362 * 363 * @param params 方法参数 364 * @param context 上下文对象 365 * @return SQL 语句 366 * @see com.mybatisflex.core.BaseMapper#selectObjectByQuery(QueryWrapper) 367 */ 368 public static String selectObjectByQuery(Map params, ProviderContext context) { 369 QueryWrapper queryWrapper = ProviderUtil.getQueryWrapper(params); 370 371 appendTableConditions(context, queryWrapper, false); 372 373 //优先构建 sql,再构建参数 374 String sql = DialectFactory.getDialect().forSelectByQuery(queryWrapper); 375 376 Object[] values = CPI.getValueArray(queryWrapper); 377 ProviderUtil.setSqlArgs(params, values); 378 379 return sql; 380 } 381 382 383 private static void appendTableConditions(ProviderContext context, QueryWrapper queryWrapper, boolean setSelectColumns) { 384 List<TableInfo> tableInfos = getTableInfos(context, queryWrapper); 385 if (CollectionUtil.isNotEmpty(tableInfos)) { 386 for (TableInfo tableInfo : tableInfos) { 387 tableInfo.appendConditions(null, queryWrapper); 388 if (setSelectColumns) { 389 CPI.setSelectColumnsIfNecessary(queryWrapper, tableInfo.getDefaultQueryColumn()); 390 } 391 CPI.setFromIfNecessary(queryWrapper, tableInfo.getSchema(), tableInfo.getTableName()); 392 } 393 } else { 394 List<QueryWrapper> childQueryWrappers = CPI.getChildSelect(queryWrapper); 395 if (CollectionUtil.isNotEmpty(childQueryWrappers)) { 396 for (QueryWrapper childQueryWrapper : childQueryWrappers) { 397 appendTableConditions(context, childQueryWrapper, setSelectColumns); 398 } 399 } 400 } 401 } 402 403 404 private static List<TableInfo> getTableInfos(ProviderContext context, QueryWrapper queryWrapper) { 405 List<TableInfo> tableInfos; 406 List<QueryTable> queryTables = CPI.getQueryTables(queryWrapper); 407 if (CollectionUtil.isNotEmpty(queryTables)) { 408 tableInfos = new ArrayList<>(); 409 for (QueryTable queryTable : queryTables) { 410 String tableNameWithSchema = queryTable.getNameWithSchema(); 411 if (StringUtil.isNotBlank(tableNameWithSchema)) { 412 TableInfo tableInfo = TableInfoFactory.ofTableName(tableNameWithSchema); 413 if (tableInfo != null) { 414 tableInfos.add(tableInfo); 415 } 416 } 417 } 418 } else { 419 tableInfos = Collections.singletonList(ProviderUtil.getTableInfo(context)); 420 } 421 return tableInfos; 422 } 423 424 425}