InsertOperation.java
package io.github.simplejdbcmapper.core;
import org.springframework.beans.BeanWrapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.util.Assert;
import io.github.simplejdbcmapper.exception.MapperException;
class InsertOperation {
private final SimpleJdbcMapperSupport sjmSupport;
// insert cache. Note that Spring SimpleJdbcInsert is thread safe.
// Map key - class name
// value - SimpleJdbcInsert
private final SimpleCache<String, SimpleJdbcInsert> insertSqlCache = new SimpleCache<>();
public InsertOperation(SimpleJdbcMapperSupport sjmSupport) {
this.sjmSupport = sjmSupport;
}
public void insert(Object object) {
Assert.notNull(object, "object must not be null");
TableMapping tableMapping = sjmSupport.getTableMapping(object.getClass());
BeanWrapper bw = sjmSupport.getBeanWrapper(object);
validateId(tableMapping, bw);
populateAutoAssignProperties(tableMapping, bw);
MapSqlParameterSource mapSqlParameterSource = createMapSqlParameterSource(tableMapping, bw);
SimpleJdbcInsert simpleJdbcInsert = insertSqlCache.get(object.getClass().getName());
if (simpleJdbcInsert == null) {
simpleJdbcInsert = createSimpleJdbcInsert(tableMapping);
// SimpleJdbcInsert is thread safe. cache it
insertSqlCache.put(object.getClass().getName(), simpleJdbcInsert);
}
if (tableMapping.isIdAutoGenerated()) {
KeyHolder kh = simpleJdbcInsert.executeAndReturnKeyHolder(mapSqlParameterSource);
// set the generated id on the object
bw.setPropertyValue(tableMapping.getIdPropertyName(), kh.getKeyAs(Object.class));
} else {
simpleJdbcInsert.execute(mapSqlParameterSource);
}
}
SimpleCache<String, SimpleJdbcInsert> getInsertSqlCache() {
return insertSqlCache;
}
private MapSqlParameterSource createMapSqlParameterSource(TableMapping tableMapping, BeanWrapper bw) {
MapSqlParameterSource mapSqlParameterSource = new MapSqlParameterSource();
for (PropertyMapping propMapping : tableMapping.getPropertyMappings()) {
Integer columnSqlType = propMapping.getEffectiveSqlType();
if (propMapping.isBinaryLargeObject()) {
InternalUtils.assignBlobMapSqlParameterSource(bw, mapSqlParameterSource, propMapping, columnSqlType,
true);
} else if (propMapping.isCharacterLargeObject()) {
InternalUtils.assignClobMapSqlParameterSource(bw, mapSqlParameterSource, propMapping, columnSqlType,
true);
} else if (propMapping.isEnum()) {
InternalUtils.assignEnumMapSqlParameterSource(bw, mapSqlParameterSource, propMapping, columnSqlType,
true);
} else {
mapSqlParameterSource.addValue(propMapping.getColumnName(),
bw.getPropertyValue(propMapping.getPropertyName()), columnSqlType);
}
}
return mapSqlParameterSource;
}
private void validateId(TableMapping tableMapping, BeanWrapper bw) {
Object idValue = bw.getPropertyValue(tableMapping.getIdPropertyName());
if (tableMapping.isIdAutoGenerated()) {
if (idValue != null) {
throw new MapperException("For insert() the property " + bw.getWrappedClass().getSimpleName() + "."
+ tableMapping.getIdPropertyName()
+ " has to be null since this insert is for an object whose id is auto generated");
}
} else {
if (idValue == null) {
throw new MapperException("For insert() the property " + bw.getWrappedClass().getSimpleName() + "."
+ tableMapping.getIdPropertyName() + " must not be null since it is not an auto generated id");
}
}
}
private void populateAutoAssignProperties(TableMapping tableMapping, BeanWrapper bw) {
if (tableMapping.hasAutoAssignProperties()) {
PropertyMapping createdOnPropMapping = tableMapping.getCreatedOnPropertyMapping();
if (createdOnPropMapping != null && sjmSupport.getRecordAuditedOnSupplier() != null) {
bw.setPropertyValue(createdOnPropMapping.getPropertyName(),
sjmSupport.getRecordAuditedOnSupplier().get());
}
PropertyMapping updatedOnPropMapping = tableMapping.getUpdatedOnPropertyMapping();
if (updatedOnPropMapping != null && sjmSupport.getRecordAuditedOnSupplier() != null) {
bw.setPropertyValue(updatedOnPropMapping.getPropertyName(),
sjmSupport.getRecordAuditedOnSupplier().get());
}
PropertyMapping createdByPropMapping = tableMapping.getCreatedByPropertyMapping();
if (createdByPropMapping != null && sjmSupport.getRecordAuditedBySupplier() != null) {
bw.setPropertyValue(createdByPropMapping.getPropertyName(),
sjmSupport.getRecordAuditedBySupplier().get());
}
PropertyMapping updatedByPropMapping = tableMapping.getUpdatedByPropertyMapping();
if (updatedByPropMapping != null && sjmSupport.getRecordAuditedBySupplier() != null) {
bw.setPropertyValue(updatedByPropMapping.getPropertyName(),
sjmSupport.getRecordAuditedBySupplier().get());
}
PropertyMapping versionPropMapping = tableMapping.getVersionPropertyMapping();
if (versionPropMapping != null) {
// version property value defaults to 1 on inserts
bw.setPropertyValue(versionPropMapping.getPropertyName(), 1);
}
}
}
private SimpleJdbcInsert createSimpleJdbcInsert(TableMapping tableMapping) {
SimpleJdbcInsert simpleJdbcInsert = new SimpleJdbcInsert(sjmSupport.getJdbcTemplate())
.withCatalogName(tableMapping.getCatalogName()).withSchemaName(tableMapping.getSchemaName())
.withTableName(tableMapping.getTableName());
// make sure SimpleJdbcInsert does not access database table meta data.
simpleJdbcInsert.setAccessTableColumnMetaData(false);
String[] columns = null;
if (tableMapping.isIdAutoGenerated()) {
// remove id from list of columns
columns = tableMapping.getPropertyMappings().stream().filter(e -> !e.isIdAnnotation())
.map(e -> e.getColumnName()).toArray(String[]::new);
} else {
columns = tableMapping.getPropertyMappings().stream().map(e -> e.getColumnName()).toArray(String[]::new);
}
simpleJdbcInsert.usingColumns(columns);
if (tableMapping.isIdAutoGenerated()) {
simpleJdbcInsert.usingGeneratedKeyColumns(tableMapping.getIdColumnName());
}
return simpleJdbcInsert;
}
}