按表

时间:2016-09-29 21:02:54

标签: java jdbc jdbi

我正在使用JDBI来查询我们的数据库。我有两个通过外键连接的表,我的查询返回两个表的连接。要将返回的值转换为对象,我已经为我的对象实现了ResultSetMapper。查询中的ResultSet包含两个表的列:t1.id, t1.name, t2.id, t2.name。如何根据表名拆分?我正在寻找这段代码:

public class T1Object {
    private long id;
    private String name;
    private T2Object t2Object;
}

public class T2Object {
    private long id;
    private String name;
}

public void map(ResultSet r) {
    String t1Name = "Table1 name";
    String t2Name = "Table2 name";

    t1ResultSet = getResultSetByTableName(r, t1Name); // looking for this function's implementation
    t2ResultSet = getResultSetByTableName(r, t2Name);

    // convert each result set to an object using it's mapper...
}

问题是Table1Table2有一些具有相同名称的列,所以我考虑更改查询以返回每列的不同名称,并解析整个ResultSet但是如果我有很多列或者我只对Table2进行更改,这将无法很好地扩展(我必须记住不仅要更改Table2的映射器,而且还要回到这里并制作变化)。

我发现了这个solution,但它看起来过于复杂。

任何想法都会非常感激....

1 个答案:

答案 0 :(得分:0)

我建议使用列名前缀作为可选的构造函数参数实现映射器:

class T1Mapper implements ResultSetMapper<T1Object> {
  public T1Mapper() { this(""); }
  public T1Mapper(String prefix) {
    this.prefix = prefix;
  }

  private final String prefix;

  T1Object map(int i, ResultSet rs, StatementContext ctx) throws SQLException {
    return new T1Object(rs.getInt(prefix + "id"),
                        rs.getString(prefix + "name"));
  }
}

// ditto for t2 mapper

因此,当您遇到需要连接多个具有共同列名称的表的情况时,请在查询中标记每一列以消除它们的歧义:

List<T1Object> handle.createQuery("select t1.id t1_id, t1.name t1_name, " +
                   "t2.id t2_id, t2.name t2_name " +
                   "from table1 t1 left join table2 t2 " +
                   "on t1.id = t2.t1_id")
      .map(new ResultSetMapper<T1Object>() {
        T1Mapper t1Mapper = new T1Mapper("t1_");
        T2Mapper t2Mapper = new T2Mapper("t2_");

        public T1Object map(int i, ResultSet rs, StatementContext ctx) {
          T1Object t1 = t1Mapper.map(i, rs, ctx);
          T2Object t2 = t2Mapper.map(i, rs, ctx);
          t1.setT2Object(t2);
          return t1;
        }
      })
      .list();

除非我没有听说过一些花哨的伎俩,否则不必为这些列名添加前缀 - 除非您想编写自定义连接行映射器用手。

我认为我们已经在v3(仍处于alpha版)中更好地解决了这个用例问题。像BeanMapper这样的所有反射映射器现在都支持列名称前缀,如上所述,开箱即用。我们还添加了JoinRowMapper,这使得这个愚蠢的简单:

@SqlQuery("select t1.id t1_id, t1.name t1_name, " +
          "t2.id t2_id, t2.name t2_name " +
          "from table1 t1 left join table2 t2 " +
          "on t1.id = t2.t1_id")
@RegisterBeanMapper(value = {T1Object.class, T2Object.class},
                    prefix = {"t1_", "t2_"})
@RegisterJoinRowMapper({T1Object.class, T2Object.class})
List<JoinRow> listJoins();

因此:

myDao.listJoins()
     .stream()
     .map(joinRow -> {
       T1Object t1 = joinRow.get(T1Object.class);
       T2Object t2 = joinRow.get(T2Object.class);

       // merge the individual entities in your join rows however you like
       t1.setT2(t2);
       return t1;
     })
     .collect(toList());