最原始的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 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 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 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,代码还不够通用,以后还要改进。

你可能感兴趣的:(Hibernate,SQL,log4j,DAO,JDBC)