最原始的O/R Mapping,比hibernate轻的多

hibernate的O/R Mapping确实很强大,但是对于查询如果要使用hibernate的Query来实现,就必须先写好mapping,对于单个表还好办,但如果是复杂的多表连接查询的话就得写一大堆mapping和Entity,稍有疏漏就会出错,那hibernate有没有提供更简单的sql query接口呢?简单到仅仅需要写个sql,并提供一个Entity的包路径(当然这个Entity bean还是要程序员来实现的),执行.list()就能轻松将返回的每行记录注入Entity,最后结果集以list返回?从而解放了程序员繁重的劳动,使开发更加敏捷呢?

带着这个疑问我看了hibernate reference,看到hibernate提供session.createSQLQuery接口,似乎可以满足我的要求,好!让我来试试看,于是有了下面的代码:

public List<Private> getPublicIndex(String startDate, String endDate) throws SQLException {
StringBuffer sql = new StringBuffer();
sql.append("select a.id as id, a.money as deposit, b.money as loan, c.money as loanleave, a.tdate as tdate")
.append(" FROM publicindex a inner join publicindex b")
.append(" on a.tdate = b.tdate and a.flag = '1' and b.flag = '2'")
.append(" inner join publicindex c")
.append(" on a.tdate = c.tdate and c.flag = '3'")
.append(" where (a.tflag = 2 or a.tflag = 3 or a.tflag = 7) and")
.append(" (b.tflag = 2 or b.tflag = 3 or b.tflag = 7) and")
.append(" (c.tflag = 2 or c.tflag = 3 or c.tflag = 7) and")
.append(" a.tdate >= to_date(?, 'yyyy-mm-dd') and")
.append(" a.tdate <= to_date(?, 'yyyy-mm-dd')")
.append(" order by a.tdate");
Session session = dao.openSession();
return session.createSQLQuery(sql.toString()).addEntity(Private.class).setParameter(0, startDate).setParameter(1, endDate).list();
}

说明下:dao是公司前辈封装的一个简单框架,同时支持jdbc和hibernate,对于Private.class,仅仅是个bean,并没有写hibernate mapping,测试发现抛了下面的异常:

org.hibernate.MappingException: Unknown entity: com.cuishen.edwview.pojo.Private

于是我就mapping了一个简单的Entity,做了个简单的单表sql查询,如下:

public List<TechnicApp> getTechnicApp(String date) throws SQLException {
String sql = "select * from technicappindex t where t.tdate = to_date(?, 'yyyy-mm-dd')";
Session session = dao.openSession();
return session.createSQLQuery(sql).addEntity(TechnicApp.class).setParameter(0, date).list();
}

说明下:将technicappindex表mapping为TechnicApp,测试通过了!看来hibernate的sql query还是不能完全脱离mapping

于是我修改了dao的代码,在jdbc返回结果集做封装的模块中加入了如下代码:

/**
* 反射POJO的setter方法,将记录中匹配的列值注入POJO,最后以List返回,
* 在不区分大小写的情况下记录中的列名(加上'set'前缀)必须和POJO中的公有setter方法名一致,
* 否则将不会被注入
* @param list 要返回的list
* @param pojoClassName String 要注入的POJO的包路径, e.g 'com.cuishen.pojo.Cat'
* @param rs ResultSet 待封装的原始结果集
*/
private static void setPOJO(List list, String pojoClassName, ResultSet rs) {
try {
ResultSetMetaData metaData = rs.getMetaData();
int columnCount = metaData.getColumnCount(); // 查询的列数
Method [] methodsToInvoke = new Method[columnCount];
Class pojo = Class.forName(pojoClassName);
Method [] methods = pojo.getMethods();
for(int i = 0; i < columnCount; i++) {
for(int j = 0; j < methods.length; j++) {
String methodName = methods[j].getName();
if(methodName.equalsIgnoreCase("set" + metaData.getColumnName(i + 1))) {
methodsToInvoke[i] = methods[j];
log4j.debug(">>>>>> method name : " + methodsToInvoke[i].getName() + " para name : " + methodsToInvoke[i].getParameterTypes()[0].getName());
log4j.debug("======= >>>>>>> column name : " + metaData.getColumnName(i + 1) + " column type : " + metaData.getColumnClassName(i + 1));
break;
}
}
}
while(rs.next()) {
Object obj = pojo.newInstance();
for(int i = 0; i < columnCount; i++) {
methodsToInvoke[i].invoke(obj, new Object[]{castValue(rs.getObject(i + 1), methodsToInvoke[i].getParameterTypes()[0])});
}
list.add(obj);
}
} catch (InstantiationException e) {
e.printStackTrace();
log4j.error(e.getMessage(), e);
} catch (IllegalAccessException e) {
e.printStackTrace();
log4j.error(e.getMessage(), e);
} catch (SQLException e) {
e.printStackTrace();
log4j.error(e.getMessage(), e);
} catch (IllegalArgumentException e) {
e.printStackTrace();
log4j.error(e.getMessage(), e);
} catch (InvocationTargetException e) {
e.printStackTrace();
log4j.error(e.getMessage(), e);
} catch (ClassNotFoundException e) {
e.printStackTrace();
log4j.error(e.getMessage(), e);
}
}
/**
* 类型强制转换
* @param source
* @param target
* @return
*/
private static Object castValue(Object source, Class target) {
if(source instanceof BigDecimal) {
if(target == Long.class) return new Long(((BigDecimal)source).longValue());
else if(target == Integer.class) return new Integer(((BigDecimal)source).intValue());
else if(target == Short.class) return new Short(((BigDecimal)source).shortValue());
else if(target == Double.class) return new Double(((BigDecimal)source).doubleValue());
else if(target == Float.class) return new Float(((BigDecimal)source).floatValue());
}
return source;
}

然后在dao里实现了新的接口:

/**
* jdbc sql查询,将记录注入POJO,结果集最终以list返回
* @param sql String sql语句
* @param params sql中的参数
* @param pojo String POJO的包路径
*/
List sqlQueryAsPOJO(String sql, Object[] params, String pojo) throws SQLException;

哈哈,现在做多表连接查询简单多啦!

public List<Private> getPublicIndex(String startDate, String endDate) throws SQLException {
StringBuffer sql = new StringBuffer();
sql.append("select a.id as id, a.money as deposit, b.money as loan, c.money as loanleave, a.tdate as tdate")
.append(" FROM publicindex a inner join publicindex b")
.append(" on a.tdate = b.tdate and a.flag = '1' and b.flag = '2'")
.append(" inner join publicindex c")
.append(" on a.tdate = c.tdate and c.flag = '3'")
.append(" where (a.tflag = 2 or a.tflag = 3 or a.tflag = 7) and")
.append(" (b.tflag = 2 or b.tflag = 3 or b.tflag = 7) and")
.append(" (c.tflag = 2 or c.tflag = 3 or c.tflag = 7) and")
.append(" a.tdate >= to_date(?, 'yyyy-mm-dd') and")
.append(" a.tdate <= to_date(?, 'yyyy-mm-dd')")
.append(" order by a.tdate");
return dao.sqlQueryAsPOJO(sql.toString(), new String[]{startDate, endDate}, "com.cuishen.edwview.pojo.Private");
}

新加的代码是对jdbc的简单封装,并没有用到hibernate,代码还不够通用,以后还要改进。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值