zoukankan      html  css  js  c++  java
  • Native Query的自定义转换器

    Hibernate管理的对象通常都有hbm配置文件或注解。有一些项目需要定义一些DTO对象,比如为了组装报表数据。对于这类不受hibernate管理的对象。在hibernate使用native sql的时候,可以自定义一些transformer来实现查询结果集到List<T>的自动映射,而不必再人工的去做这个转换。

    下面是在泛型DAO里面定义的一个泛型方法。注意,这个方法的泛型是与泛型DAO类定义的泛型不同。

    View Code
    @SuppressWarnings("unchecked")
    protected <T1> List<T1> getResultByNativeQuery(final String sql,
    final Class<T1> targetClass, final Object[] args,final int...otherArgs) {
    List
    <T1> list = (List<T1>) getHibernateTemplate().executeFind(
    new HibernateCallback() {
    @Override
    public Object doInHibernate(Session session)
    throws HibernateException, SQLException {
    Query query
    = session
    .createSQLQuery(sql)
    .setResultTransformer(
    new WithoutHibernateMappingTransformer<T1>(
    targetClass));
    if (args != null) {
    for (int i = 0; i < args.length; i++) {
    query.setParameter(i, args[i]);
    }
    }
    int position=args.length;
    for (int i = 0; i < otherArgs.length; i++) {
    query.setParameter(position
    +i, otherArgs[i]);
    }
    return query.list();
    }
    });
    return list;
    }

    对应的Transfer需要实现自Hibernate提供的接口:ResultTransformer

    View Code
    import java.math.BigDecimal;
    import java.util.List;
    import java.util.StringTokenizer;

    import org.apache.commons.lang.StringUtils;
    import org.hibernate.HibernateException;
    import org.hibernate.PropertyNotFoundException;
    import org.hibernate.property.ChainedPropertyAccessor;
    import org.hibernate.property.PropertyAccessor;
    import org.hibernate.property.PropertyAccessorFactory;
    import org.hibernate.property.Setter;
    import org.hibernate.transform.ResultTransformer;

    public class WithoutHibernateMappingTransformer<TT> implements
    ResultTransformer {

    private static final long serialVersionUID = -5199190581393587893L;
    private final Class<TT> resultClass;
    private Setter[] setters;
    private PropertyAccessor propertyAccessor;

    public WithoutHibernateMappingTransformer(Class<TT> resultClass) {
    if (resultClass == null)
    throw new IllegalArgumentException("resultClass cannot be null");
    this.resultClass = resultClass;
    propertyAccessor
    = new ChainedPropertyAccessor(new PropertyAccessor[] {
    PropertyAccessorFactory.getPropertyAccessor(resultClass,
    null),
    PropertyAccessorFactory.getPropertyAccessor(
    "field") });
    }

    public Object transformTuple(Object[] tuple, String[] aliases) {
    Object result;
    try {
    if (setters == null) {
    setters
    = new Setter[aliases.length];
    for (int i = 0; i < aliases.length; i++) {
    String alias
    = convertColumnToProperty(aliases[i]);
    if (alias != null) {
    try {
    setters[i]
    = propertyAccessor.getSetter(
    resultClass, alias);
    }
    catch (PropertyNotFoundException e) {
    continue;
    }
    }
    }
    }
    result
    = resultClass.newInstance();
    for (int i = 0; i < aliases.length; i++) {
    if (setters[i] != null) {
    if (tuple[i].getClass().equals(BigDecimal.class)) {
    setters[i].set(result, ((BigDecimal) tuple[i])
    .longValue(),
    null);
    }
    else{
    setters[i].set(result, tuple[i],
    null);
    }
    }
    }
    }
    catch (InstantiationException e) {
    throw new HibernateException("Could not instantiate resultclass: "
    + resultClass.getName());
    }
    catch (IllegalAccessException e) {
    throw new HibernateException("Could not instantiate resultclass: "
    + resultClass.getName());
    }
    return result;
    }

    /**
    * Converts the specified 'XXX_YYY_ZZZ'-like column name to its
    * 'xxxYyyZzz'-like Java property name.
    *
    *
    @param columnName
    * the column name
    *
    @return the Java property name
    */
    public String convertColumnToProperty(String columnName) {
    columnName
    = columnName.toLowerCase();
    StringBuffer buff
    = new StringBuffer(columnName.length());
    StringTokenizer st
    = new StringTokenizer(columnName, "_");
    while (st.hasMoreTokens()) {
    buff.append(StringUtils.capitalize(st.nextToken()));
    }
    buff.setCharAt(
    0, Character.toLowerCase(buff.charAt(0)));
    return buff.toString();
    }


    @SuppressWarnings(
    "unchecked")
    public List transformList(List collection) {
    return (List<TT>)collection;
    }

    public static void main(String args[]) {
    WithoutHibernateMappingTransformer
    <String> transfer = new WithoutHibernateMappingTransformer<String>(
    String.
    class);
    System.out.println(transfer.convertColumnToProperty(
    "CPCID"));
    System.out.println(transfer.convertColumnToProperty(
    "XXX_YYY_ZZZ"));
    }
    }

    另外,对于Hibernate管理的类,可以使用Query query = session.createSQLQuery(sql).addEntity(entityClass)来实现映射。不过,这种方式就需要hbm文件里有相应的property映射Oracle的字段。

    注意:

    1。Oracle的字段别名都是大写,所以不能使用Hibernate提供的现成方式,这样会导致通过大写的别名去java类里找相应的字段,这会找不到的:

    sess.createSQLQuery("SELECT NAME, BIRTHDATE FROM CATS") .setResultTransformer(Transformers.aliasToBean(CatDTO.class))

    2. 转换器中针对Oracle返回类型与应用之间的数据类型显示进行了转换。比如Oracle返回的BigDecimal与Long之间的转换。

    3.约定是Oracle中的下划线来分隔单词。具体参测试。

    4.即使对于Hibernate的受管对象,也是可以使用转换器的。前提实体里定义了相应字段的set方法。

    5. 注意到jdk5以后,java的返回类型值是可以被复盖的。比如 Object可以使用T这样的泛型变量替代。

    6.在使用转换器的过程中,发现数据库字段如果是date类似,那么oracle在某些jdbc驱动下会将date转换为java中的java.sql.Date. 由于java.sql.Date会trunc掉时分秒,只保留年月日,这样导致应用程序中对应的属性只有年月日,而数据库中的字段即包含年月日+时分秒. 解决的办法有二种:1.将数据库的字段由date改为timestamp. oracle的所有驱动都会将timestamp转换成java中的java.sql.Timestamp类型,而不存在trunc时分秒. 缺点是这样应用程序中改动起来比较麻烦.

    2.我推荐的方式: 数据库仍然使用date,但是针对datesource添加oracle.jdbc.V8Compatible=true的连接属性.

    比如

    <bean id="parentDataSource"
    class
    ="org.springframework.jdbc.datasource.DriverManagerDataSource"
    abstract
    ="true">
    <property name="driverClassName"
    value
    ="oracle.jdbc.driver.OracleDriver" />
    <!--注意如何注入key-value的properties属性-->
    <property name="connectionProperties">
    <props>
    <prop key="oracle.jdbc.V8Compatible">true</prop>
    </props>
    </property>
    </bean>

    或者在jdbc的应用中:

    public static void main(String[] args) {     
        try {     
               Class.forName("oracle.jdbc.OracleDriver");     
               Properties prop=new Properties();     
               prop.setProperty("user","system");     
               prop.setProperty("password","dba");     
               prop.setProperty("oracle.jdbc.V8Compatible","true");     
               java.sql.Connection connection1 = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:orcl", prop);     
               System.out.println(connection1);     
               System.out.println(connection1.getMetaData().getDriverName()+" "+connection1.getMetaData().getDriverVersion());     
               ResultSet rs = connection1.createStatement().executeQuery("select date1,date2 from t_test");     
        
            while (rs.next()) {     
                String value1 = rs.getString("DATE1");     
                System.out.println("DATE1=" + value1);     
                String value2 = rs.getString("DATE2");     
                System.out.println("DATE2=" + value2);     
            }     
           }     
           catch (Exception exception1) {     
               exception1.printStackTrace();     
           }     
        
    } 
    

  • 相关阅读:
    ajax参数解析
    利用HTML5新特性改变浏览器地址后不刷新页面
    JsDoc脚本注释文档生成
    sublime中配置Java 环境
    使用Node.js+Socket.IO搭建WebSocket实时应用【转载】
    js实现前端下载文件
    android JB3上怎样更改Camera拍照的quality
    关于_ENV(lua5.2 or later)
    hadoop-2.7.1安装笔记
    JavaScript的类及面向对象编程
  • 原文地址:https://www.cnblogs.com/highriver/p/1970241.html
Copyright © 2011-2022 走看看