通过Hibernate的org.hibernate.Query将Clob数据加载为String(eager)

时间:2014-05-10 13:21:05

标签: java oracle hibernate flex

我需要使用Hibernate 从clob Oracle列获取一个字符串,而不使用延迟加载而不使用Criteria查询。它目前返回一个代理类(例如$ Proxy30),但我需要一个String(或者我可以转换为String的东西)。根据调试器,代理用于oracle.sql.CLOB。

当我使用Criteria查询(只有该字段的常规Column注释映射)时,这很好用。但是我们有一个区域可以“构建”一个使用简单的org.hibernate.Query和AliasToEntityMapResultTransformer.INSTANCE的自定义SQL查询,这就是代理问题出现的地方。因为它只是一个org.hibernate.Query,我认为它根本不是指我的注释映射,所以我不认为弄乱注释会有所帮助。

由于此处不使用Criteria查询(我们正在为某些高级搜索报告要求构建查询字符串),我应该如何研究以找到解决方法?或者甚至更好,我做这项工作的努力是什么?

这也适用于Apache Flex应用程序 - 我需要将类型作为String(而不是CLOB)用于客户端的数据传输对象。也许其他Flex开发人员之前已经解决了这个问题?

Query query = getSessionFactory().getCurrentSession().createSqlQuery(sql);
query.setResultTransformer(AliasToEntityMapResultTransformer.INSTANCE);
List... resultlist = ...query.list();
resultlist.iterator();
//iterate results...
Object shouldBeAString = (Object)result.get("CLOB_COLUMN_NAME");
//The object above should be a String but is a $Proxy30
//Debugger shows an "h" property of type SerializableClobProxy

如果我需要一个自定义的“ResultTransformer” - 任何指向正常文档的链接都会受到赞赏......

2 个答案:

答案 0 :(得分:2)

我遇到了同样的问题,各种链接建议将spring升级到4.0.1+并将hibernate升级到4.3.x,但这并没有任何区别。然后我遇到了这个解决了我的问题的链接。作者为Clob编写了一个自定义的ResultTransformer,然后将其设置为您查询的变换器而不是AliasToEntityMapResultTransformer。

http://javatechtricks.blogspot.co.uk/2012/12/hibernate-clob-to-string-conversion.html

以下文章中的代码:

public class MyResultTransformer extends BasicTransformerAdapter {

 public final static MyResultTransformer INSTANCE;
 static {
  INSTANCE = new MyResultTransformer();
 }

 private MyResultTransformer() {

 }
 private static final long serialVersionUID = 1L;

 @Override
 public Object transformTuple(Object[] tuple, String[] aliases) {
  Map<String, Object> map = new HashMap<String, Object>();
  for (int i = 0; i < aliases.length; i++) {
   Object t = tuple[i];
   if (t != null && t instanceof Clob) {
    Clob c = (Clob) tuple[i];
    try {
     ByteArrayOutputStream bos = new ByteArrayOutputStream();
     IOUtils.copy(c.getAsciiStream(), bos);
     t = new String(bos.toByteArray());
    } catch (SQLException e) {
     e.printStackTrace();
    } catch (IOException e) {
     e.printStackTrace();
    }
   }
   map.put(aliases[i], t);
  }
  return map;
 }
}

然后在你的代码中替换

query.setResultTransformer(AliasToEntityMapResultTransformer.INSTANCE);

query.setResultTransformer(MyResultTransformer.INSTANCE);

此外,替代解决方案可能是更改列类型,我自己没有尝试过。

  

JDBC大对象   blob和clob类型提供了映射   java.sql包中的Blob和Clob类。如果你正在处理   真正的大价值,你最好的选择是将属性声明为   无论是Blob还是Clob,即使这引入了显式JDBC   依赖于您的数据对象,它可以轻松地让Hibernate充分利用   JDBC功能只在您需要时延迟加载属性值

     

如果您不担心数据太大,您可以放心   你自己这个直接的JDBC接口,将属性类型声明为   字符串或字节[],并使用文本或二进制映射它。这些对应   到CLOB和VARBINARY的SQL列类型(Oracle中的RAW,中的BYTEA)   PostgreSQL)分别和将值立即加载到   加载对象时的属性

来源:http://oreilly.com/java/excerpts/harnessing-hibernate/hibernate-types.html

答案 1 :(得分:0)

谢谢你,我修改了一点使用clob方法getSubString的解决方案:只有一个例外,可以捕获。

public Object transformTuple(final Object[] tuple, final String[] aliases) {
        final Map<String, Object> result = new LinkedHashMap<>(tuple.length);
        for (int i = 0; i < tuple.length; i++) {
            Object object = tuple[i];
            if (object instanceof Clob) {
                object = clobToString((Clob) object);
            }
            final String alias = aliases[i];
            if (alias != null) {
                result.put(alias, object);
            }
        }
        return result;
    }

    private String clobToString(final Clob clob) {
        try {
            return clob.getSubString(1, (int) clob.length());
        } catch (final SQLException e) {
            throw new RuntimeException("Error while converting clob : " + clob, e);
        }
    }