DATAJDBC-97 - Basic implementation of all CRUD methods.
Original pull request: #5.
This commit is contained in:
committed by
Oliver Gierke
parent
38a91d97a0
commit
2181d8d3c6
@@ -19,11 +19,35 @@ import org.springframework.data.mapping.model.BasicPersistentEntity;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
/**
|
||||
* meta data a repository might need for implementing persistence operations for instances of type {@code T}
|
||||
* @author Jens Schauder
|
||||
*/
|
||||
public class JdbcPersistentEntity<T> extends BasicPersistentEntity<T, JdbcPersistentProperty> {
|
||||
|
||||
private String tableName;
|
||||
private String idColumn;
|
||||
|
||||
public JdbcPersistentEntity(TypeInformation<T> information) {
|
||||
super(information);
|
||||
}
|
||||
|
||||
public String getTableName() {
|
||||
|
||||
if (tableName == null)
|
||||
tableName = getType().getSimpleName();
|
||||
|
||||
return tableName;
|
||||
}
|
||||
|
||||
public String getIdColumn() {
|
||||
|
||||
if (idColumn == null)
|
||||
idColumn = getIdProperty().getName();
|
||||
|
||||
return idColumn;
|
||||
}
|
||||
|
||||
public Object getIdValue(T instance) {
|
||||
return getPropertyAccessor(instance).getProperty(getIdProperty());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
|
||||
/**
|
||||
* meta data about a property to be used by repository implementations.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
*/
|
||||
public class JdbcPersistentProperty extends AnnotationBasedPersistentProperty<JdbcPersistentProperty> {
|
||||
@@ -43,4 +45,8 @@ public class JdbcPersistentProperty extends AnnotationBasedPersistentProperty<Jd
|
||||
protected Association<JdbcPersistentProperty> createAssociation() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getColumnName() {
|
||||
return getName();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,49 +15,62 @@
|
||||
*/
|
||||
package org.springframework.data.jdbc.repository;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.convert.ClassGeneratingEntityInstantiator;
|
||||
import org.springframework.data.convert.EntityInstantiator;
|
||||
import org.springframework.data.jdbc.mapping.model.JdbcPersistentEntity;
|
||||
import org.springframework.data.jdbc.mapping.model.JdbcPersistentProperty;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PreferredConstructor;
|
||||
import org.springframework.data.mapping.PropertyHandler;
|
||||
import org.springframework.data.mapping.model.MappingException;
|
||||
import org.springframework.data.mapping.model.ParameterValueProvider;
|
||||
|
||||
/**
|
||||
* maps a ResultSet to an entity of type {@code T}
|
||||
*
|
||||
* @author Jens Schauder
|
||||
*/
|
||||
class EntityRowMapper<T> implements org.springframework.jdbc.core.RowMapper<T> {
|
||||
|
||||
private final PersistentEntity<T, ?> entity;
|
||||
private final JdbcPersistentEntity<T> entity;
|
||||
|
||||
EntityRowMapper(PersistentEntity<T, ?> entity) {
|
||||
private final EntityInstantiator instantiator = new ClassGeneratingEntityInstantiator();
|
||||
|
||||
EntityRowMapper(JdbcPersistentEntity<T> entity) {
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
|
||||
try {
|
||||
T t = createInstance(rs);
|
||||
|
||||
T t = createInstance();
|
||||
entity.doWithProperties((PropertyHandler) property -> {
|
||||
setProperty(rs, t, property);
|
||||
});
|
||||
|
||||
entity.doWithProperties((PropertyHandler) property -> {
|
||||
setProperty(rs, t, property);
|
||||
});
|
||||
|
||||
return t;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(String.format("Could not instantiate %s", entity.getType()));
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
private T createInstance() throws InstantiationException, IllegalAccessException, InvocationTargetException {
|
||||
return (T) entity.getPersistenceConstructor().getConstructor().newInstance();
|
||||
private T createInstance(ResultSet rs) {
|
||||
return instantiator.createInstance(entity, new ParameterValueProvider<JdbcPersistentProperty>() {
|
||||
@Override
|
||||
public <T> T getParameterValue(PreferredConstructor.Parameter<T, JdbcPersistentProperty> parameter) {
|
||||
try {
|
||||
return (T) rs.getObject(parameter.getName());
|
||||
} catch (SQLException e) {
|
||||
throw new MappingException(String.format("Couldn't read column %s from ResultSet.", parameter.getName()));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setProperty(ResultSet rs, T t, PersistentProperty property) {
|
||||
|
||||
try {
|
||||
property.getSetter().invoke(t, rs.getObject(property.getName()));
|
||||
entity.getPropertyAccessor(t).setProperty(property, rs.getObject(property.getName()));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(String.format("Couldn't set property %s.", property.getName()), e);
|
||||
}
|
||||
|
||||
@@ -16,14 +16,13 @@
|
||||
package org.springframework.data.jdbc.repository;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
import javax.sql.DataSource;
|
||||
import org.springframework.data.jdbc.mapping.model.JdbcPersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.jdbc.mapping.model.JdbcPersistentProperty;
|
||||
import org.springframework.data.mapping.PropertyHandler;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
|
||||
@@ -37,117 +36,116 @@ public class SimpleJdbcRepository<T, ID extends Serializable> implements CrudRep
|
||||
|
||||
private final JdbcPersistentEntity<T> entity;
|
||||
private final NamedParameterJdbcOperations template;
|
||||
private final SqlGenerator sql;
|
||||
|
||||
private final String findOneSql;
|
||||
private final String insertSql;
|
||||
private final EntityRowMapper<T> entityRowMapper;
|
||||
|
||||
public SimpleJdbcRepository(JdbcPersistentEntity<T> entity, DataSource dataSource) {
|
||||
|
||||
this.entity = entity;
|
||||
this.template = new NamedParameterJdbcTemplate(dataSource);
|
||||
|
||||
findOneSql = createFindOneSelectSql();
|
||||
insertSql = createInsertSql();
|
||||
entityRowMapper = new EntityRowMapper<T>(entity);
|
||||
sql = new SqlGenerator(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S extends T> S save(S entity) {
|
||||
|
||||
template.update(insertSql, getPropertyMap(entity));
|
||||
template.update(sql.getInsert(), getPropertyMap(entity));
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S extends T> Iterable<S> save(Iterable<S> entities) {
|
||||
return null;
|
||||
|
||||
Map<String, ?>[] batchValues = StreamSupport
|
||||
.stream(entities.spliterator(), false)
|
||||
.map(i -> getPropertyMap(i))
|
||||
.toArray(size -> new Map[size]);
|
||||
|
||||
template.batchUpdate(sql.getInsert(), batchValues);
|
||||
|
||||
return entities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T findOne(ID id) {
|
||||
|
||||
return template.queryForObject(
|
||||
findOneSql,
|
||||
sql.getFindOne(),
|
||||
new MapSqlParameterSource("id", id),
|
||||
new EntityRowMapper<T>(entity)
|
||||
entityRowMapper
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(ID id) {
|
||||
return false;
|
||||
|
||||
return template.queryForObject(
|
||||
sql.getExists(),
|
||||
new MapSqlParameterSource("id", id),
|
||||
Boolean.class
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<T> findAll() {
|
||||
return null;
|
||||
return template.query(sql.getFindAll(), entityRowMapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<T> findAll(Iterable<ID> ids) {
|
||||
return null;
|
||||
return template.query(sql.getFindAllInList(), new MapSqlParameterSource("ids", ids), entityRowMapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long count() {
|
||||
return 0;
|
||||
return template.getJdbcOperations().queryForObject(sql.getCount(), Long.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(ID id) {
|
||||
|
||||
template.update(sql.getDeleteById(), new MapSqlParameterSource("id", id));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(T entity) {
|
||||
public void delete(T instance) {
|
||||
|
||||
template.update(
|
||||
sql.getDeleteById(),
|
||||
new MapSqlParameterSource("id",
|
||||
entity.getIdValue(instance)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(Iterable<? extends T> entities) {
|
||||
|
||||
template.update(
|
||||
sql.getDeleteByList(),
|
||||
new MapSqlParameterSource("ids",
|
||||
StreamSupport
|
||||
.stream(entities.spliterator(), false)
|
||||
.map(entity::getIdValue)
|
||||
.collect(Collectors.toList())
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAll() {
|
||||
|
||||
template.getJdbcOperations().update(sql.getDeleteAll());
|
||||
}
|
||||
|
||||
private String createFindOneSelectSql() {
|
||||
|
||||
String tableName = entity.getType().getSimpleName();
|
||||
String idColumn = entity.getIdProperty().getName();
|
||||
|
||||
return String.format("select * from %s where %s = :id", tableName, idColumn);
|
||||
}
|
||||
|
||||
private String createInsertSql() {
|
||||
|
||||
List<String> propertyNames = new ArrayList<>();
|
||||
entity.doWithProperties((PropertyHandler) persistentProperty -> propertyNames.add(persistentProperty.getName()));
|
||||
|
||||
String insertTemplate = "insert into %s (%s) values (%s)";
|
||||
|
||||
String tableName = entity.getType().getSimpleName();
|
||||
|
||||
String tableColumns = propertyNames.stream().collect(Collectors.joining(", "));
|
||||
String parameterNames = propertyNames.stream().collect(Collectors.joining(", :", ":", ""));
|
||||
|
||||
return String.format(insertTemplate, tableName, tableColumns, parameterNames);
|
||||
}
|
||||
|
||||
private <S extends T> Map<String, Object> getPropertyMap(final S entity) {
|
||||
private <S extends T> Map<String, Object> getPropertyMap(final S instance) {
|
||||
|
||||
Map<String, Object> parameters = new HashMap<>();
|
||||
|
||||
this.entity.doWithProperties(new PropertyHandler() {
|
||||
this.entity.doWithProperties(new PropertyHandler<JdbcPersistentProperty>() {
|
||||
@Override
|
||||
public void doWithPersistentProperty(PersistentProperty persistentProperty) {
|
||||
try {
|
||||
parameters.put(persistentProperty.getName(), persistentProperty.getGetter().invoke(entity));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(String.format("Couldn't get value of property %s", persistentProperty.getName()));
|
||||
}
|
||||
public void doWithPersistentProperty(JdbcPersistentProperty persistentProperty) {
|
||||
parameters.put(persistentProperty.getColumnName(), entity.getPropertyAccessor(instance).getProperty(persistentProperty));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* 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 org.springframework.data.jdbc.repository;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import org.springframework.data.jdbc.mapping.model.JdbcPersistentEntity;
|
||||
import org.springframework.data.mapping.PropertyHandler;
|
||||
|
||||
/**
|
||||
* @author Jens Schauder
|
||||
*/
|
||||
class SqlGenerator {
|
||||
|
||||
private final String findOneSql;
|
||||
private final String findAllSql;
|
||||
private final String findAllInListSql;
|
||||
|
||||
private final String existsSql;
|
||||
private final String countSql;
|
||||
|
||||
private final String insertSql;
|
||||
private final String deleteByIdSql;
|
||||
private final String deleteAllSql;
|
||||
private final String deleteByListSql;
|
||||
|
||||
<T> SqlGenerator(JdbcPersistentEntity<T> entity) {
|
||||
|
||||
findOneSql = createFindOneSelectSql(entity);
|
||||
findAllSql = createFindAllSql(entity);
|
||||
findAllInListSql = createFindAllInListSql(entity);
|
||||
|
||||
existsSql = createExistsSql(entity);
|
||||
countSql = createCountSql(entity);
|
||||
|
||||
insertSql = createInsertSql(entity);
|
||||
|
||||
deleteByIdSql = createDeleteSql(entity);
|
||||
deleteAllSql = createDeleteAllSql(entity);
|
||||
deleteByListSql = createDeleteByListSql(entity);
|
||||
}
|
||||
|
||||
String getFindAllInList() {
|
||||
return findAllInListSql;
|
||||
}
|
||||
|
||||
String getFindAll() {
|
||||
return findAllSql;
|
||||
}
|
||||
|
||||
String getExists() {
|
||||
return existsSql;
|
||||
}
|
||||
|
||||
String getFindOne() {
|
||||
return findOneSql;
|
||||
}
|
||||
|
||||
String getInsert() {
|
||||
return insertSql;
|
||||
}
|
||||
|
||||
String getCount() {
|
||||
return countSql;
|
||||
}
|
||||
|
||||
String getDeleteById() {
|
||||
return deleteByIdSql;
|
||||
}
|
||||
|
||||
String getDeleteAll() {
|
||||
return deleteAllSql;
|
||||
}
|
||||
|
||||
String getDeleteByList() {
|
||||
return deleteByListSql;
|
||||
}
|
||||
private String createFindOneSelectSql(JdbcPersistentEntity<?> entity) {
|
||||
return String.format("select * from %s where %s = :id", entity.getTableName(), entity.getIdColumn());
|
||||
}
|
||||
|
||||
private String createFindAllSql(JdbcPersistentEntity<?> entity) {
|
||||
return String.format("select * from %s", entity.getTableName());
|
||||
}
|
||||
|
||||
private String createFindAllInListSql(JdbcPersistentEntity<?> entity) {
|
||||
return String.format(String.format("select * from %s where %s in (:ids)", entity.getTableName(), entity.getIdColumn()), entity.getTableName());
|
||||
}
|
||||
|
||||
private String createExistsSql(JdbcPersistentEntity<?> entity) {
|
||||
return String.format("select count(*) from %s where %s = :id", entity.getTableName(), entity.getIdColumn());
|
||||
}
|
||||
|
||||
private <T> String createCountSql(JdbcPersistentEntity<T> entity) {
|
||||
return String.format("select count(*) from %s", entity.getTableName(), entity.getIdColumn());
|
||||
}
|
||||
|
||||
private String createInsertSql(JdbcPersistentEntity<?> entity) {
|
||||
|
||||
List<String> propertyNames = new ArrayList<>();
|
||||
entity.doWithProperties((PropertyHandler) persistentProperty -> propertyNames.add(persistentProperty.getName()));
|
||||
|
||||
String insertTemplate = "insert into %s (%s) values (%s)";
|
||||
|
||||
String tableName = entity.getType().getSimpleName();
|
||||
|
||||
String tableColumns = propertyNames.stream().collect(Collectors.joining(", "));
|
||||
String parameterNames = propertyNames.stream().collect(Collectors.joining(", :", ":", ""));
|
||||
|
||||
return String.format(insertTemplate, tableName, tableColumns, parameterNames);
|
||||
}
|
||||
|
||||
private String createDeleteSql(JdbcPersistentEntity entity) {
|
||||
return String.format("delete from %s where %s = :id", entity.getTableName(), entity.getIdColumn());
|
||||
}
|
||||
|
||||
private String createDeleteAllSql(JdbcPersistentEntity entity) {
|
||||
return String.format("delete from %s", entity.getTableName());
|
||||
}
|
||||
|
||||
private String createDeleteByListSql(JdbcPersistentEntity entity) {
|
||||
return String.format("delete from %s where id in (:ids)", entity.getTableName());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user