001/* 002 * Copyright (c) 2022-2025, 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(Collection) 123 * @see com.mybatisflex.core.FlexConsts#METHOD_INSERT_BATCH 124 */ 125 public static String insertBatch(Map params, ProviderContext context) { 126 Collection<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 * selectOneById 的 SQL 构建。 293 * 294 * @param params 方法参数 295 * @param context 上下文对象 296 * @return SQL 语句 297 * @see com.mybatisflex.core.BaseMapper#selectOneById(Serializable) 298 */ 299 public static String selectOneById(Map params, ProviderContext context) { 300 Object[] primaryValues = ProviderUtil.getPrimaryValues(params); 301 302 FlexAssert.notEmpty(primaryValues, "primaryValues"); 303 304 TableInfo tableInfo = ProviderUtil.getTableInfo(context); 305 306 Object[] allValues = ArrayUtil.concat(primaryValues, tableInfo.buildTenantIdArgs()); 307 308 ProviderUtil.setSqlArgs(params, allValues); 309 310 return DialectFactory.getDialect().forSelectOneEntityById(tableInfo); 311 } 312 313 314 /** 315 * selectListByIds 的 SQL 构建。 316 * 317 * @param params 方法参数 318 * @param context 上下文对象 319 * @return SQL 语句 320 * @see com.mybatisflex.core.BaseMapper#selectListByIds(Collection) 321 */ 322 public static String selectListByIds(Map params, ProviderContext context) { 323 Object[] primaryValues = ProviderUtil.getPrimaryValues(params); 324 325 FlexAssert.notEmpty(primaryValues, "primaryValues"); 326 327 TableInfo tableInfo = ProviderUtil.getTableInfo(context); 328 329 Object[] allValues = ArrayUtil.concat(primaryValues, tableInfo.buildTenantIdArgs()); 330 ProviderUtil.setSqlArgs(params, allValues); 331 332 return DialectFactory.getDialect().forSelectEntityListByIds(tableInfo, primaryValues); 333 } 334 335 336 /** 337 * selectListByQuery 的 SQL 构建。 338 * 339 * @param params 方法参数 340 * @param context 上下文对象 341 * @return SQL 语句 342 * @see com.mybatisflex.core.BaseMapper#selectListByQuery(QueryWrapper) 343 */ 344 public static String selectListByQuery(Map params, ProviderContext context) { 345 QueryWrapper queryWrapper = ProviderUtil.getQueryWrapper(params); 346 347 appendTableConditions(context, queryWrapper, true); 348 349 //优先构建 sql,再构建参数 350 String sql = DialectFactory.getDialect().forSelectByQuery(queryWrapper); 351 352 Object[] values = CPI.getValueArray(queryWrapper); 353 ProviderUtil.setSqlArgs(params, values); 354 355 return sql; 356 } 357 358 359 /** 360 * selectCountByQuery 的 SQL 构建。 361 * 362 * @param params 方法参数 363 * @param context 上下文对象 364 * @return SQL 语句 365 * @see com.mybatisflex.core.BaseMapper#selectObjectByQuery(QueryWrapper) 366 */ 367 public static String selectObjectByQuery(Map params, ProviderContext context) { 368 QueryWrapper queryWrapper = ProviderUtil.getQueryWrapper(params); 369 370 appendTableConditions(context, queryWrapper, false); 371 372 //优先构建 sql,再构建参数 373 String sql = DialectFactory.getDialect().forSelectByQuery(queryWrapper); 374 375 Object[] values = CPI.getValueArray(queryWrapper); 376 ProviderUtil.setSqlArgs(params, values); 377 378 return sql; 379 } 380 381 382 private static void appendTableConditions(ProviderContext context, QueryWrapper queryWrapper, boolean setSelectColumns) { 383 List<TableInfo> tableInfos = getTableInfos(context, queryWrapper); 384 if (CollectionUtil.isNotEmpty(tableInfos)) { 385 for (TableInfo tableInfo : tableInfos) { 386 tableInfo.appendConditions(null, queryWrapper); 387 if (setSelectColumns) { 388 CPI.setSelectColumnsIfNecessary(queryWrapper, tableInfo.getDefaultQueryColumn()); 389 } 390 CPI.setFromIfNecessary(queryWrapper, tableInfo.getSchema(), tableInfo.getTableName()); 391 } 392 } else { 393 List<QueryWrapper> childQueryWrappers = CPI.getChildSelect(queryWrapper); 394 if (CollectionUtil.isNotEmpty(childQueryWrappers)) { 395 for (QueryWrapper childQueryWrapper : childQueryWrappers) { 396 appendTableConditions(context, childQueryWrapper, setSelectColumns); 397 } 398 } 399 } 400 } 401 402 403 private static List<TableInfo> getTableInfos(ProviderContext context, QueryWrapper queryWrapper) { 404 List<TableInfo> tableInfos; 405 List<QueryTable> queryTables = CPI.getQueryTables(queryWrapper); 406 if (CollectionUtil.isNotEmpty(queryTables)) { 407 tableInfos = new ArrayList<>(); 408 for (QueryTable queryTable : queryTables) { 409 String tableNameWithSchema = queryTable.getNameWithSchema(); 410 if (StringUtil.hasText(tableNameWithSchema)) { 411 TableInfo tableInfo = TableInfoFactory.ofTableName(tableNameWithSchema); 412 if (tableInfo != null) { 413 tableInfos.add(tableInfo); 414 } 415 } 416 } 417 } else { 418 tableInfos = Collections.singletonList(ProviderUtil.getTableInfo(context)); 419 } 420 return tableInfos; 421 } 422 423 424}