【问题标题】:NamedParameterJdbcTemplate and composite keyNamedParameterJdbcTemplate 和复合键
【发布时间】:2013-12-04 21:16:13
【问题描述】:

我编写了一个方法来检索带有 NamedParameterJdbcTemplate 的条目列表:

public final Map<K,V> findAll(final Collection<K> keys) {
    if (keys == null) {
        return null;
    }
    MapSqlParameterSource parameters = new MapSqlParameterSource();
    parameters.addValue("ids", keys);
    List<V> values = new NamedParameterJdbcTemplate(datasource).query("select * from TABLE where id in ( :ids )", parameters, mapper);          

    Map<K,V> results = new HashMap<K, V>();
    for (V v : values) {
        results.put((K) v.getId(), v);              
    }        
    return results;
}

但这只有在键是简单类型时才有效。 我无法使其与主键一起使用,例如:

public class CompositeKey implements Serializable {

    private long field1;
    private long field2;
}

如何使用复合键使我的 findAll() 方法工作?

【问题讨论】:

  • 你没有问任何问题。
  • 这不是关于 Java 或 Spring JDBC 的问题。这是关于一般 SQL 语法和元组比较的。请更新您的问题并包括您正在使用的数据库类型。
  • 另一方面 - 您将在使用 NamedParameterJdbcTemplate... 构建查询时遇到问题,因此问题的两个方面都是有效的。但是您需要知道要构造的 SQL 查询应该是什么样子。
  • 我的问题与 SQL 无关。指令:ids 仅对 NamedParameterJdbcTemplate 有效,我想知道如何处理复合主键。与 SQL 无关。

标签: java spring-data jdbctemplate named-parameters


【解决方案1】:

您的问题应该分部分回答:

  • 如何结合IN和元组比较编写SELECT
  • 如何使用NamedParameterJdbcTemplate 编写这样的SELECT

如何使用复合PK查询多个对象

PostgreSQL / MySQL(也可能是 Oracle):

 SELECT * FROM foo WHERE (field1, field2) IN ((1, 1), (1, 3));

SQL Server(有点小技巧;也适用于 PostgreSQL):

SELECT * FROM foo 
INNER JOIN (VALUES (1, 1), (1, 3)) AS _CONDITION(field1, field2) ON
        foo.field1 = _CONDITION.field1 AND foo.field2 = _CONDITION.field2;

如何使用 NamedParameterJdbcTemplate 进行查询

使用List&lt;Object[]&gt; 作为您的参数类型。有关此主题,请参阅 JavaDoc for NamedParameterUtilsofficial documentation

使用地图参数的示例

public List<MyObject> findByIds(Collection<MyKey> keys) {
    List<Object[]> keyTuples = new ArrayList<Object[]>(keys.size());
    for (MyKey key : keys) {
        keyTuples.add(new Object[] { key.getField1(), key.getField2() });
    }
    jdbcTemplate.query("SELECT * FROM my_table WHERE (field1, field2) IN (:keys)", 
            Collections.singletonMap("keys", keyTuples), new MyObjectRowMapper());
}

【讨论】:

  • @pavel-coral 谢谢。这肯定是正确的答案,无论如何我无法清楚地理解如何用代码翻译你的解释。我定义了一个像select * from TABLE where (field1, field2) in (:field1, :field2) 这样的sql 字符串,然后如果我执行BeanPropertySqlParameterSource parameters = new BeanPropertySqlParameterSource(key); String sql = NamedParameterUtils.substituteNamedParameters(sql, parameters); 方法,我得到了sql select * from TABLE where (field1, field2) in (?, ?)。现在我被困在翻译复合键集合Collecion&lt;K&gt; keys
  • @patrizio.munzi 我添加了使用单个地图参数的简单示例。自己回答的方式有点复杂。
  • 顺便说一句。如果你真的想使用反射,那么使用 Spring 的BeanWrapperImpl。但我建议宁愿使用接口(例如在某些CompoundKey 接口上实现Object[] getTuples() 方法)或通用entity / key 超类,而不是使用泛型方法/类型。
【解决方案2】:

我不得不使用一种我并不完全满意的解决方法,但它确实有效。 我必须手动翻译列表数组对象中的 bean 列表,然后将数组对象列表传递给 NamedParameterJdbcTemplate。

如果有人有更优雅的解决方案,请与我分享。

findAll 方法的最终实现

    public final Map<K,V> findAll(final Collection<K> keys) throws DaoMethodNotSupportedException {

    List<Object[]> keyObjsList = new ArrayList<Object[]>();
    ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(":field1 :field2");
    for (K key : keys) {
        SqlParameterSource paramSource = new BeanPropertySqlParameterSource(key);
        Object[] keyParams = NamedParameterUtils.buildValueArray(parsedSql, paramSource, null);
        keyObjsList.add(keyParams);
    }

    MapSqlParameterSource parameters = new MapSqlParameterSource();
    parameters.addValue("primaryKeys", keyObjsList);

    List<V> values = new NamedParameterJdbcTemplate(datasource).query("select * from TABLE where (field1, field2) in ( :primaryKeys )", parameters, valueMapper);          

    for (V v : values) {
        results.put((K) v.getPrimaryKey(), v);
    }        
    return results;
}

谢谢大家

【讨论】:

    猜你喜欢
    • 2014-11-04
    • 1970-01-01
    • 1970-01-01
    • 2012-08-23
    • 1970-01-01
    • 2023-03-08
    • 2016-02-18
    • 1970-01-01
    • 2013-04-01
    相关资源
    最近更新 更多