com.landawn.abacus.jdbc.dao.CrudDao Maven / Gradle / Ivy
/*
* Copyright (c) 2021, Haiyang Li.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.landawn.abacus.jdbc.dao;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.landawn.abacus.annotation.Beta;
import com.landawn.abacus.condition.Condition;
import com.landawn.abacus.condition.ConditionFactory;
import com.landawn.abacus.condition.ConditionFactory.CF;
import com.landawn.abacus.exception.DuplicatedResultException;
import com.landawn.abacus.jdbc.AbstractQuery;
import com.landawn.abacus.jdbc.IsolationLevel;
import com.landawn.abacus.jdbc.Jdbc;
import com.landawn.abacus.jdbc.JdbcUtil;
import com.landawn.abacus.jdbc.SQLTransaction;
import com.landawn.abacus.jdbc.annotation.NonDBOperation;
import com.landawn.abacus.parser.ParserUtil;
import com.landawn.abacus.parser.ParserUtil.BeanInfo;
import com.landawn.abacus.util.Fn;
import com.landawn.abacus.util.N;
import com.landawn.abacus.util.QueryUtil;
import com.landawn.abacus.util.SQLBuilder;
import com.landawn.abacus.util.u.Nullable;
import com.landawn.abacus.util.u.Optional;
import com.landawn.abacus.util.u.OptionalBoolean;
import com.landawn.abacus.util.u.OptionalByte;
import com.landawn.abacus.util.u.OptionalChar;
import com.landawn.abacus.util.u.OptionalDouble;
import com.landawn.abacus.util.u.OptionalFloat;
import com.landawn.abacus.util.u.OptionalInt;
import com.landawn.abacus.util.u.OptionalLong;
import com.landawn.abacus.util.u.OptionalShort;
import com.landawn.abacus.util.stream.Stream.StreamEx;
/**
* The Interface CrudDao.
*
* @param
* @param use {@code Void} if there is no id defined/annotated with {@code @Id} in target entity class {@code T}.
* @param {@code SQLBuilder} used to generate sql scripts. Only can be {@code SQLBuilder.PSC/PAC/PLC}
* @see JdbcUtil#prepareQuery(javax.sql.DataSource, String)
* @see JdbcUtil#prepareNamedQuery(javax.sql.DataSource, String)
* @see JdbcUtil#beginTransaction(javax.sql.DataSource, IsolationLevel, boolean)
* @see Dao
* @see com.landawn.abacus.condition.ConditionFactory
* @see com.landawn.abacus.condition.ConditionFactory.CF
*/
public interface CrudDao> extends Dao {
/**
*
*
* @return
*/
@NonDBOperation
default Jdbc.BiRowMapper idExtractor() {
return null;
}
/**
*
* @return
* @throws SQLException
* @throws UnsupportedOperationException
* @deprecated unsupported Operation
*/
@Deprecated
@NonDBOperation
default ID generateId() throws SQLException, UnsupportedOperationException {
throw new UnsupportedOperationException();
}
/**
*
* @param entityToInsert
* @return
* @throws SQLException
*/
ID insert(final T entityToInsert) throws SQLException;
/**
*
* @param entityToInsert
* @param propNamesToInsert
* @return
* @throws SQLException
*/
ID insert(final T entityToInsert, final Collection propNamesToInsert) throws SQLException;
/**
*
* @param namedInsertSQL
* @param entityToInsert
* @return
* @throws SQLException
*/
ID insert(final String namedInsertSQL, final T entityToInsert) throws SQLException;
/**
*
* @param entities
* @return
* @throws SQLException
*/
default List batchInsert(final Collection extends T> entities) throws SQLException {
return batchInsert(entities, JdbcUtil.DEFAULT_BATCH_SIZE);
}
/**
*
* @param entities
* @param batchSize
* @return
* @throws SQLException
*/
List batchInsert(final Collection extends T> entities, final int batchSize) throws SQLException;
/**
*
* @param entities
* @param propNamesToInsert
* @return
* @throws SQLException
*/
default List batchInsert(final Collection extends T> entities, final Collection propNamesToInsert) throws SQLException {
return batchInsert(entities, propNamesToInsert, JdbcUtil.DEFAULT_BATCH_SIZE);
}
/**
*
* @param entities
* @param propNamesToInsert
* @param batchSize
* @return
* @throws SQLException
*/
List batchInsert(final Collection extends T> entities, final Collection propNamesToInsert, final int batchSize) throws SQLException;
/**
*
* @param namedInsertSQL
* @param entities
* @return
* @throws SQLException
*/
@Beta
default List batchInsert(final String namedInsertSQL, final Collection extends T> entities) throws SQLException {
return batchInsert(namedInsertSQL, entities, JdbcUtil.DEFAULT_BATCH_SIZE);
}
/**
*
* @param namedInsertSQL
* @param entities
* @param batchSize
* @return
* @throws SQLException
*/
@Beta
List batchInsert(final String namedInsertSQL, final Collection extends T> entities, final int batchSize) throws SQLException;
/**
* Returns an {@code OptionalBoolean} describing the value in the first row/column if it exists, otherwise return an empty {@code OptionalBoolean}.
*
* @param singleSelectPropName
* @param id
* @return
* @throws SQLException
* @see ConditionFactory
* @see ConditionFactory.CF
* @see AbstractQuery#queryForBoolean()
*/
OptionalBoolean queryForBoolean(final String singleSelectPropName, final ID id) throws SQLException;
/**
* Returns an {@code OptionalChar} describing the value in the first row/column if it exists, otherwise return an empty {@code OptionalChar}.
*
* @param singleSelectPropName
* @param id
* @return
* @throws SQLException
* @see ConditionFactory
* @see ConditionFactory.CF
* @see AbstractQuery#queryForChar()
*/
OptionalChar queryForChar(final String singleSelectPropName, final ID id) throws SQLException;
/**
* Returns an {@code OptionalByte} describing the value in the first row/column if it exists, otherwise return an empty {@code OptionalByte}.
*
* @param singleSelectPropName
* @param id
* @return
* @throws SQLException
* @see ConditionFactory
* @see ConditionFactory.CF
* @see AbstractQuery#queryForByte()
*/
OptionalByte queryForByte(final String singleSelectPropName, final ID id) throws SQLException;
/**
* Returns an {@code OptionalShort} describing the value in the first row/column if it exists, otherwise return an empty {@code OptionalShort}.
*
* @param singleSelectPropName
* @param id
* @return
* @throws SQLException
* @see ConditionFactory
* @see ConditionFactory.CF
* @see AbstractQuery#queryForShort()
*/
OptionalShort queryForShort(final String singleSelectPropName, final ID id) throws SQLException;
/**
* Returns an {@code OptionalInt} describing the value in the first row/column if it exists, otherwise return an empty {@code OptionalInt}.
*
* @param singleSelectPropName
* @param id
* @return
* @throws SQLException
* @see ConditionFactory
* @see ConditionFactory.CF
* @see AbstractQuery#queryForInt()
*/
OptionalInt queryForInt(final String singleSelectPropName, final ID id) throws SQLException;
/**
* Returns an {@code OptionalLong} describing the value in the first row/column if it exists, otherwise return an empty {@code OptionalLong}.
*
* @param singleSelectPropName
* @param id
* @return
* @throws SQLException
* @see ConditionFactory
* @see ConditionFactory.CF
* @see AbstractQuery#queryForLong()
*/
OptionalLong queryForLong(final String singleSelectPropName, final ID id) throws SQLException;
/**
* Returns an {@code OptionalFloat} describing the value in the first row/column if it exists, otherwise return an empty {@code OptionalFloat}.
*
* @param singleSelectPropName
* @param id
* @return
* @throws SQLException
* @see ConditionFactory
* @see ConditionFactory.CF
* @see AbstractQuery#queryForFloat()
*/
OptionalFloat queryForFloat(final String singleSelectPropName, final ID id) throws SQLException;
/**
* Returns an {@code OptionalDouble} describing the value in the first row/column if it exists, otherwise return an empty {@code OptionalDouble}.
*
* @param singleSelectPropName
* @param id
* @return
* @throws SQLException
* @see ConditionFactory
* @see ConditionFactory.CF
* @see AbstractQuery#queryForDouble()
*/
OptionalDouble queryForDouble(final String singleSelectPropName, final ID id) throws SQLException;
/**
* Returns a {@code Nullable} describing the value in the first row/column if it exists, otherwise return an empty {@code Nullable}.
*
* @param singleSelectPropName
* @param id
* @return
* @throws SQLException
* @see ConditionFactory
* @see ConditionFactory.CF
* @see AbstractQuery#queryForString()
*/
Nullable queryForString(final String singleSelectPropName, final ID id) throws SQLException;
/**
* Returns a {@code Nullable} describing the value in the first row/column if it exists, otherwise return an empty {@code Nullable}.
*
* @param singleSelectPropName
* @param id
* @return
* @throws SQLException
* @see ConditionFactory
* @see ConditionFactory.CF
* @see AbstractQuery#queryForDate()
*/
Nullable queryForDate(final String singleSelectPropName, final ID id) throws SQLException;
/**
* Returns a {@code Nullable} describing the value in the first row/column if it exists, otherwise return an empty {@code Nullable}.
*
* @param singleSelectPropName
* @param id
* @return
* @throws SQLException
* @see ConditionFactory
* @see ConditionFactory.CF
* @see AbstractQuery#queryForTime()
*/
Nullable queryForTime(final String singleSelectPropName, final ID id) throws SQLException;
/**
* Returns a {@code Nullable} describing the value in the first row/column if it exists, otherwise return an empty {@code Nullable}.
*
* @param singleSelectPropName
* @param id
* @return
* @throws SQLException
* @see ConditionFactory
* @see ConditionFactory.CF
* @see AbstractQuery#queryForTimestamp()
*/
Nullable queryForTimestamp(final String singleSelectPropName, final ID id) throws SQLException;
/**
* Returns a {@code Nullable} describing the value in the first row/column if it exists, otherwise return an empty {@code Nullable}.
*
* @param singleSelectPropName
* @param id
* @return
* @throws SQLException
* @see ConditionFactory
* @see ConditionFactory.CF
* @see AbstractQuery#queryForBytes()
*/
Nullable queryForBytes(final String singleSelectPropName, final ID id) throws SQLException;
/**
* Returns a {@code Nullable} describing the value in the first row/column if it exists, otherwise return an empty {@code Nullable}.
*
* @param
* @param targetValueClass
* @param singleSelectPropName
* @param id
* @return
* @throws SQLException
* @see ConditionFactory
* @see ConditionFactory.CF
* @see AbstractQuery#queryForSingleResult(Class)
*/
Nullable queryForSingleResult(final Class extends V> targetValueClass, final String singleSelectPropName, final ID id) throws SQLException;
/**
* Returns an {@code Optional} describing the value in the first row/column if it exists, otherwise return an empty {@code Optional}.
*
* @param the value type
* @param targetValueClass
* @param singleSelectPropName
* @param id
* @return
* @throws SQLException
* @see ConditionFactory
* @see ConditionFactory.CF
* @see AbstractQuery#queryForSingleNonNull(Class)
*/
Optional queryForSingleNonNull(final Class extends V> targetValueClass, final String singleSelectPropName, final ID id) throws SQLException;
/**
* Returns an {@code Optional} describing the value in the first row/column if it exists, otherwise return an empty {@code Optional}.
*
* @param the value type
* @param singleSelectPropName
* @param id
* @param rowMapper
* @return
* @throws SQLException
* @see ConditionFactory
* @see ConditionFactory.CF
* @see AbstractQuery#queryForSingleNonNull(Class)
*/
@Beta
Optional queryForSingleNonNull(final String singleSelectPropName, final ID id, final Jdbc.RowMapper extends V> rowMapper) throws SQLException;
/**
* Returns a {@code Nullable} describing the value in the first row/column if it exists, otherwise return an empty {@code Nullable}.
* And throws {@code DuplicatedResultException} if more than one record found.
*
* @param the value type
* @param targetValueClass
* @param singleSelectPropName
* @param id
* @return
* @throws DuplicatedResultException if more than one record found by the specified {@code id} (or {@code condition}).
* @throws SQLException
* @see ConditionFactory
* @see ConditionFactory.CF
* @see AbstractQuery#queryForUniqueResult(Class)
*/
Nullable queryForUniqueResult(final Class extends V> targetValueClass, final String singleSelectPropName, final ID id)
throws DuplicatedResultException, SQLException;
/**
* Returns an {@code Optional} describing the value in the first row/column if it exists, otherwise return an empty {@code Optional}.
*
* @param the value type
* @param targetValueClass
* @param singleSelectPropName
* @param id
* @return
* @throws DuplicatedResultException if more than one record found by the specified {@code id} (or {@code condition}).
* @throws SQLException
* @see ConditionFactory
* @see ConditionFactory.CF
* @see AbstractQuery#queryForUniqueNonNull(Class)
*/
Optional queryForUniqueNonNull(final Class extends V> targetValueClass, final String singleSelectPropName, final ID id)
throws DuplicatedResultException, SQLException;
/**
* Returns an {@code Optional} describing the value in the first row/column if it exists, otherwise return an empty {@code Optional}.
*
* @param the value type
* @param singleSelectPropName
* @param id
* @param rowMapper
* @return
* @throws DuplicatedResultException if more than one record found by the specified {@code id} (or {@code condition}).
* @throws SQLException
* @see ConditionFactory
* @see ConditionFactory.CF
* @see AbstractQuery#queryForUniqueNonNull(Class)
*/
@Beta
Optional queryForUniqueNonNull(final String singleSelectPropName, final ID id, final Jdbc.RowMapper extends V> rowMapper)
throws DuplicatedResultException, SQLException;
/**
* Returns the record found by the specified {@code id} or an empty {@code Optional} if no record is found.
*
* @param id
* @return
* @throws DuplicatedResultException if more than one record found by the specified {@code id} (or {@code condition}).
* @throws SQLException
*/
default Optional get(final ID id) throws DuplicatedResultException, SQLException {
return Optional.ofNullable(gett(id));
}
/**
* Returns the record found by the specified {@code id} or an empty {@code Optional} if no record is found.
*
* @param id
* @param selectPropNames all properties(columns) will be selected, excluding the properties of joining entities, if the specified {@code selectPropNames} is {@code null}.
* @return
* @throws DuplicatedResultException if more than one record found by the specified {@code id} (or {@code condition}).
* @throws SQLException
*/
default Optional get(final ID id, final Collection selectPropNames) throws DuplicatedResultException, SQLException {
return Optional.ofNullable(gett(id, selectPropNames));
}
/**
* Returns the record found by the specified {@code id} or {@code null} if no record is found.
*
* @param id
* @return
* @throws DuplicatedResultException if more than one record found by the specified {@code id} (or {@code condition}).
* @throws SQLException
*/
T gett(final ID id) throws DuplicatedResultException, SQLException;
/**
* Returns the record found by the specified {@code id} or {@code null} if no record is found.
*
* @param id
* @param selectPropNames all properties(columns) will be selected, excluding the properties of joining entities, if the specified {@code selectPropNames} is {@code null}.
*
* @return
* @throws DuplicatedResultException if more than one record found by the specified {@code id} (or {@code condition}).
* @throws SQLException
*/
T gett(final ID id, final Collection selectPropNames) throws DuplicatedResultException, SQLException;
/**
*
*
* @param ids
* @return
* @throws DuplicatedResultException if the size of result is bigger than the size of input {@code ids}.
* @throws SQLException
*/
default List batchGet(final Collection extends ID> ids) throws DuplicatedResultException, SQLException {
return batchGet(ids, (Collection) null);
}
/**
*
* @param ids
* @param batchSize
* @return
* @throws DuplicatedResultException if the size of result is bigger than the size of input {@code ids}.
* @throws SQLException
*/
default List batchGet(final Collection extends ID> ids, final int batchSize) throws DuplicatedResultException, SQLException {
return batchGet(ids, (Collection) null, batchSize);
}
/**
*
*
* @param ids
* @param selectPropNames all properties(columns) will be selected, excluding the properties of joining entities, if the specified {@code selectPropNames} is {@code null}. all properties(columns) will be selected, excluding the properties of joining entities, if the specified {@code selectPropNames} is {@code null}.
* @return
* @throws DuplicatedResultException if the size of result is bigger than the size of input {@code ids}.
* @throws SQLException
*/
default List batchGet(final Collection extends ID> ids, final Collection selectPropNames) throws DuplicatedResultException, SQLException {
return batchGet(ids, selectPropNames, JdbcUtil.DEFAULT_BATCH_SIZE);
}
/**
*
* @param ids
* @param selectPropNames all properties(columns) will be selected, excluding the properties of joining entities, if the specified {@code selectPropNames} is {@code null}. all properties(columns) will be selected, excluding the properties of joining entities, if {@code selectPropNames} is {@code null}.
* @param batchSize
* @return
* @throws DuplicatedResultException if the size of result is bigger than the size of input {@code ids}.
* @throws SQLException
*/
List batchGet(final Collection extends ID> ids, final Collection selectPropNames, final int batchSize)
throws DuplicatedResultException, SQLException;
/**
*
* @param id
* @return true, if successful
* @throws SQLException
* @see AbstractQuery#exists()
*/
boolean exists(final ID id) throws SQLException;
/**
*
* @param id
* @return
* @throws SQLException
* @see AbstractQuery#notExists()
*/
@Beta
default boolean notExists(final ID id) throws SQLException {
return !exists(id);
}
/**
* Count the records in db by input {@code ids}.
* @param ids
* @return
* @throws SQLException
*/
@Beta
int count(final Collection extends ID> ids) throws SQLException;
/**
*
* @param entityToUpdate
* @return
* @throws SQLException
*/
int update(final T entityToUpdate) throws SQLException;
/**
*
* @param entityToUpdate
* @param propNamesToUpdate
* @return
* @throws SQLException
*/
int update(final T entityToUpdate, final Collection propNamesToUpdate) throws SQLException;
/**
*
* @param propName
* @param propValue
* @param id
* @return
* @throws SQLException
*/
default int update(final String propName, final Object propValue, final ID id) throws SQLException {
final Map updateProps = new HashMap<>();
updateProps.put(propName, propValue);
return update(updateProps, id);
}
/**
*
* @param updateProps
* @param id
* @return
* @throws SQLException
*/
int update(final Map updateProps, final ID id) throws SQLException;
/**
*
* @param entities
* @return
* @throws SQLException
*/
default int batchUpdate(final Collection extends T> entities) throws SQLException {
return batchUpdate(entities, JdbcUtil.DEFAULT_BATCH_SIZE);
}
/**
*
* @param entities
* @param batchSize
* @return
* @throws SQLException
*/
int batchUpdate(final Collection extends T> entities, final int batchSize) throws SQLException;
/**
*
* @param entities
* @param propNamesToUpdate
* @return
* @throws SQLException
*/
default int batchUpdate(final Collection extends T> entities, final Collection propNamesToUpdate) throws SQLException {
return batchUpdate(entities, propNamesToUpdate, JdbcUtil.DEFAULT_BATCH_SIZE);
}
/**
*
* @param entities
* @param propNamesToUpdate
* @param batchSize
* @return
* @throws SQLException
*/
int batchUpdate(final Collection extends T> entities, final Collection propNamesToUpdate, final int batchSize) throws SQLException;
/**
* Execute {@code add} and return the added entity if the record doesn't, otherwise, {@code update} is executed and updated db record is returned.
*
* @param entity
* @return
* @throws SQLException
*/
default T upsert(final T entity) throws SQLException {
N.checkArgNotNull(entity, "entity");
final Class> cls = entity.getClass();
@SuppressWarnings("deprecation")
final List idPropNameList = QueryUtil.getIdFieldNames(cls); // must not empty.
return upsert(entity, idPropNameList);
}
/**
*
* @param entity
* @param uniquePropNamesForQuery
* @return
* @throws SQLException
*/
default T upsert(final T entity, final List uniquePropNamesForQuery) throws SQLException {
N.checkArgNotNull(entity, "entity");
N.checkArgNotEmpty(uniquePropNamesForQuery, "uniquePropNamesForQuery");
final Condition cond = CF.eqAnd(entity, uniquePropNamesForQuery);
return upsert(entity, cond);
}
/**
* Execute {@code add} and return the added entity if the record doesn't, otherwise, {@code update} is executed and updated db record is returned.
*
* @param entity
* @param cond to verify if the record exists or not.
* @return
* @throws SQLException
* @see ConditionFactory
* @see ConditionFactory.CF
*/
@Override
default T upsert(final T entity, final Condition cond) throws SQLException {
N.checkArgNotNull(entity, "entity");
N.checkArgNotNull(cond, "cond");
final T dbEntity = findOnlyOne(cond).orElseNull();
if (dbEntity == null) {
insert(entity);
return entity;
} else {
final Class> cls = entity.getClass();
@SuppressWarnings("deprecation")
final List idPropNameList = QueryUtil.getIdFieldNames(cls);
N.merge(entity, dbEntity, false, N.newHashSet(idPropNameList));
update(dbEntity);
return dbEntity;
}
}
/**
*
* @param entities
* @return
* @throws SQLException
*/
default List batchUpsert(final Collection extends T> entities) throws SQLException {
return batchUpsert(entities, JdbcUtil.DEFAULT_BATCH_SIZE);
}
/**
*
* @param entities
* @param batchSize
* @return
* @throws SQLException
*/
default List batchUpsert(final Collection extends T> entities, final int batchSize) throws SQLException {
N.checkArgPositive(batchSize, "batchSize");
if (N.isEmpty(entities)) {
return new ArrayList<>();
}
final T entity = N.firstOrNullIfEmpty(entities);
final Class> cls = entity.getClass();
@SuppressWarnings("deprecation")
final List idPropNameList = QueryUtil.getIdFieldNames(cls); // must not empty.
return batchUpsert(entities, idPropNameList, batchSize);
}
/**
*
* @param entities
* @param uniquePropNamesForQuery
* @return
* @throws SQLException
*/
default List batchUpsert(final Collection extends T> entities, final List uniquePropNamesForQuery) throws SQLException {
return batchUpsert(entities, uniquePropNamesForQuery, JdbcUtil.DEFAULT_BATCH_SIZE);
}
/**
*
* @param entities
* @param uniquePropNamesForQuery
* @param batchSize
* @return
* @throws SQLException
*/
default List batchUpsert(final Collection extends T> entities, final List uniquePropNamesForQuery, final int batchSize) throws SQLException {
N.checkArgPositive(batchSize, "batchSize");
N.checkArgNotEmpty(uniquePropNamesForQuery, "uniquePropNamesForQuery");
if (N.isEmpty(entities)) {
return new ArrayList<>();
}
final T first = N.firstOrNullIfEmpty(entities);
final Class> cls = first.getClass();
final List propNameListForQuery = uniquePropNamesForQuery;
final BeanInfo entityInfo = ParserUtil.getBeanInfo(cls);
final com.landawn.abacus.util.function.Function idExtractorFunc = DaoUtil.createIdExtractor(propNameListForQuery, entityInfo);
final List ids = N.map(entities, idExtractorFunc);
final List dbEntities = batchGet(ids, batchSize);
final Map dbIdEntityMap = StreamEx.of(dbEntities).toMap(idExtractorFunc, Fn.identity(), Fn.ignoringMerger());
final Map> map = StreamEx.of(entities).groupTo(it -> dbIdEntityMap.containsKey(idExtractorFunc.apply(it)), Fn.identity());
final List entitiesToUpdate = map.get(true);
final List entitiesToInsert = map.get(false);
final List result = new ArrayList<>(entities.size());
final SQLTransaction tran = N.notEmpty(entitiesToInsert) && N.notEmpty(entitiesToUpdate) ? JdbcUtil.beginTransaction(dataSource()) : null;
try {
if (N.notEmpty(entitiesToInsert)) {
batchInsert(entitiesToInsert, batchSize);
result.addAll(entitiesToInsert);
}
if (N.notEmpty(entitiesToUpdate)) {
final Set ignoredPropNames = N.newHashSet(propNameListForQuery);
@SuppressWarnings("deprecation")
final List idPropNameList = QueryUtil.getIdFieldNames(cls);
if (N.notEmpty(idPropNameList)) {
ignoredPropNames.addAll(idPropNameList);
}
final List dbEntitiesToUpdate = StreamEx.of(entitiesToUpdate)
.map(it -> N.merge(it, dbIdEntityMap.get(idExtractorFunc.apply(it)), false, ignoredPropNames))
.toList();
batchUpdate(dbEntitiesToUpdate, batchSize);
result.addAll(dbEntitiesToUpdate);
}
if (tran != null) {
tran.commit();
}
} finally {
if (tran != null) {
tran.rollbackIfNotCommitted();
}
}
return result;
}
/**
*
* @param entity
* @return true, if successful
* @throws SQLException
*/
default boolean refresh(final T entity) throws SQLException {
N.checkArgNotNull(entity, "entity");
final Class> cls = entity.getClass();
final Collection propNamesToRefresh = JdbcUtil.getSelectPropNames(cls);
return refresh(entity, propNamesToRefresh);
}
/**
*
* @param entity
* @param propNamesToRefresh
* @return {@code false} if no record found by the ids in the specified {@code entity}.
* @throws SQLException
*/
@SuppressWarnings("deprecation")
default boolean refresh(final T entity, Collection propNamesToRefresh) throws SQLException {
N.checkArgNotNull(entity, "entity");
N.checkArgNotEmpty(propNamesToRefresh, "propNamesToRefresh");
final Class> cls = entity.getClass();
final List idPropNameList = QueryUtil.getIdFieldNames(cls); // must not empty.
final BeanInfo entityInfo = ParserUtil.getBeanInfo(cls);
final ID id = DaoUtil.extractId(entity, idPropNameList, entityInfo);
final Collection selectPropNames = DaoUtil.getRefreshSelectPropNames(propNamesToRefresh, idPropNameList);
final T dbEntity = gett(id, selectPropNames);
if (dbEntity == null) {
return false;
} else {
N.merge(dbEntity, entity, propNamesToRefresh);
return true;
}
}
/**
*
* @param entities
* @return the count of refreshed entities.
* @throws SQLException
*/
default int batchRefresh(final Collection extends T> entities) throws SQLException {
return batchRefresh(entities, JdbcUtil.DEFAULT_BATCH_SIZE);
}
/**
*
* @param entities
* @param batchSize
* @return the count of refreshed entities.
* @throws SQLException
*/
default int batchRefresh(final Collection extends T> entities, final int batchSize) throws SQLException {
if (N.isEmpty(entities)) {
return 0;
}
final T first = N.firstOrNullIfEmpty(entities);
final Class> cls = first.getClass();
final Collection propNamesToRefresh = JdbcUtil.getSelectPropNames(cls);
return batchRefresh(entities, propNamesToRefresh, batchSize);
}
/**
*
* @param entities
* @param propNamesToRefresh
* @return the count of refreshed entities.
* @throws SQLException
*/
default int batchRefresh(final Collection extends T> entities, final Collection propNamesToRefresh) throws SQLException {
return batchRefresh(entities, propNamesToRefresh, JdbcUtil.DEFAULT_BATCH_SIZE);
}
/**
*
* @param entities
* @param propNamesToRefresh
* @param batchSize
* @return the count of refreshed entities.
* @throws SQLException
*/
@SuppressWarnings("deprecation")
default int batchRefresh(final Collection extends T> entities, Collection propNamesToRefresh, final int batchSize) throws SQLException {
N.checkArgNotEmpty(propNamesToRefresh, "propNamesToRefresh");
N.checkArgPositive(batchSize, "batchSize");
if (N.isEmpty(entities)) {
return 0;
}
final T first = N.firstOrNullIfEmpty(entities);
final Class> cls = first.getClass();
final List idPropNameList = QueryUtil.getIdFieldNames(cls); // must not empty.
final BeanInfo entityInfo = ParserUtil.getBeanInfo(cls);
final com.landawn.abacus.util.function.Function idExtractorFunc = DaoUtil.createIdExtractor(idPropNameList, entityInfo);
final Map> idEntityMap = StreamEx.of(entities).groupTo(idExtractorFunc, Fn.identity());
final Collection selectPropNames = DaoUtil.getRefreshSelectPropNames(propNamesToRefresh, idPropNameList);
final List dbEntities = batchGet(idEntityMap.keySet(), selectPropNames, batchSize);
if (N.isEmpty(dbEntities)) {
return 0;
} else {
return dbEntities.stream().mapToInt(dbEntity -> {
final ID id = idExtractorFunc.apply(dbEntity);
final List tmp = idEntityMap.get(id);
if (N.notEmpty(tmp)) {
for (T entity : tmp) {
N.merge(dbEntity, entity, propNamesToRefresh);
}
}
return N.size(tmp);
}).sum();
}
}
/**
*
* @param entity
* @return
* @throws SQLException
*/
int delete(final T entity) throws SQLException;
/**
* Delete by id.
*
* @param id
* @return
* @throws SQLException
*/
int deleteById(final ID id) throws SQLException;
/**
*
* @param entities
* @return
* @throws SQLException
*/
default int batchDelete(final Collection extends T> entities) throws SQLException {
return batchDelete(entities, JdbcUtil.DEFAULT_BATCH_SIZE);
}
/**
*
* @param entities
* @param batchSize
* @return
* @throws SQLException
*/
int batchDelete(final Collection extends T> entities, final int batchSize) throws SQLException;
// /**
// *
// * @param entities
// * @param onDeleteAction It should be defined and done in DB server side.
// * @return
// * @throws SQLException
// */
// @Beta
// default int batchDelete(final Collection extends T> entities, final OnDeleteAction onDeleteAction) throws SQLException {
// return batchDelete(entities, onDeleteAction, DEFAULT_BATCH_SIZE);
// }
//
// /**
// *
// * @param entities
// * @param onDeleteAction It should be defined and done in DB server side.
// * @param batchSize
// * @return
// * @throws SQLException
// */
// @Beta
// int batchDelete(final Collection extends T> entities, final OnDeleteAction onDeleteAction, final int batchSize) throws SQLException;
/**
*
* @param ids
* @return
* @throws SQLException
*/
default int batchDeleteByIds(final Collection extends ID> ids) throws SQLException {
return batchDeleteByIds(ids, JdbcUtil.DEFAULT_BATCH_SIZE);
}
/**
*
* @param ids
* @param batchSize
* @return
* @throws SQLException
*/
int batchDeleteByIds(final Collection extends ID> ids, final int batchSize) throws SQLException;
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy