I want to support the feature that combine multiple SqlParamterSource
to a one SqlParameterSource
. For example, When save a domain object to the database, I want to bind retrieving values from domain object and other object(e.g. login user object) to an SQL using NamedParameterJdbcOperations
.
WDYT?
Code sample:
Account newAccount = new Account();
// ...
KeyHolder keyHolder = new GeneratedKeyHolder();
jdbcOperations.update(
"INSERT INTO accounts (name, email, created_at, created_by) " +
"VALUES(:name, :email, current_timestamp, :operatorId)",
SqlParameterSource.combine(
new BeanPropertySqlParameterSource(newAccount), // retrieving 'name' and 'email'
new BeanPropertySqlParameterSource(operator)), // retrieving 'operatorId'
keyHolder);
// ...
public interface SqlParameterSource {
// …
static SqlParameterSource combine(SqlParameterSource... sources) {
return new CompositeSqlParameterSource(sources);
}
public static class CompositeSqlParameterSource implements SqlParameterSource {
private final Map<String, SqlParameterSource> cache = new HashMap<>();
private final SqlParameterSource[] sources;
private CompositeSqlParameterSource(SqlParameterSource... sources) {
this.sources = sources;
}
@Override
public boolean hasValue(String paramName) {
return cache.computeIfAbsent(paramName,
x -> Stream.of(sources).filter(s -> s.hasValue(paramName)).findFirst().orElse(null)) != null;
}
@Override
public Object getValue(String paramName) {
return hasValue(paramName) ? cache.get(paramName).getValue(paramName) : null;
}
@Override
public String getTypeName(String paramName) {
return hasValue(paramName) ? cache.get(paramName).getTypeName(paramName) : null;
}
@Override
public int getSqlType(String paramName) {
return hasValue(paramName) ? cache.get(paramName).getSqlType(paramName) : TYPE_UNKNOWN;
}
@Override
public String[] getParameterNames() {
return Stream.of(sources)
.map(SqlParameterSource::getParameterNames)
.flatMap(Stream::of).distinct()
.toArray(String[]::new);
}
}
}
Comment From: snicoll
See #24032