【问题标题】:ColumnTransformer in hibernate休眠中的ColumnTransformer
【发布时间】:2015-04-28 14:47:21
【问题描述】:

我有一个实体,我使用ColumnTransformer 来绑定和提取值:

@Entity
class BPoint {
    @Id
    private Integer id;

    @ColumnTransformer(read = "astext(shape)", write = "toshape(?)")
    private Shape shape;

}

还有道:

class BPointDao {
    @Autowired
    private EntityManager em;

    @Override
    public Page<BPoint> findAll(Pageable pageable) {
        Query q = em.createQuery("from BPoint");
        List<BPoint> r = q.getResultList();
        int total = em.createQuery("select count(*)  from BPoint").getFirstResult();
        return new PageImpl(r, pageable, total);
    }
    @Override
    public Integer save(BPoint hbds) {
        em.persist(hbds);
        return hbds.getId();
    }
}

它可以工作,但是一旦我必须做一些需要使用 sql 函数的查询,我就会遇到一些问题,以这个有效的本机 sql 为例:

select * from BPoint h where inside(h.shape, 100) = 1;

首先我尝试像这样使用 hql:

Query q = em.createNativeQuery("select astext(shape) from BPoint h where inside(h.shape, ?) = 1");

但是我发现生成的sql包含类似

的东西

...... where inside(astext(h.shape),100).....

在sql函数inside中似乎使用了ColumnTransformer read值,这不是预期的。

所以我尝试像这样使用本机 sql 查询:

Query q = em.createNativeQuery("select * from BPoint h where inside(h.shape, ? = 1");

不是sql可以执行,但是结果不能正确映射。

然后我必须像这样手动添加select fileds

Query q = em.createNativeQuery("select id,astext(shape) from BPoint h where inside(h.shape, ? = 1");

但是如果我的实体有很多文件说它超过 20 个呢?如果某些列名称更改了怎么办?

是否有其他方法可以满足我的要求?

【问题讨论】:

  • 你为什么不尝试使用ResultTransformer执行本机sql和映射结果
  • 我目前使用的是原生 sql,但是我必须手动计算 sql 中的文件,因为该表包含近 100 多列。
  • 你说native sql可以执行,但是结果不能正确映射。如果你写一个ResultTransformer 来映射它会怎样

标签: java hibernate jpa orm jpql


【解决方案1】:

首先尝试为您的本机查询提供返回类型:

Query q = em.createNativeQuery("select * from BPoint h where inside(h.shape, ? = 1", BPoint.clss);
List<BPoint> result = q.getResultList();

或者你可以尝试这样做:

Session session = em.unwrap(Session.class);
List<BPoint> points = (List<BPoint>) session.createSQLQuery("SELECT {h.*} FROM BPoint {h} WHERE inside({h}.shape, ? = 1")
    .addEntity("h", BPoint.class)
.list();

Hibernate 特定的 API 允许您将本机查询结果映射到实体。

【讨论】:

  • 可能我没有说清楚,我不能在原生查询中使用select * ..,如果是这样,hibernate不能将结果集映射到实体,因为没有使用ColumnTransformer的值.
【解决方案2】:

您可以创建一个自定义拦截器并“修复”SQL 以将所有“inside(astext(#REF)) 替换为 inside(#REF)

您必须覆盖 org.hibernate.Interceptor#onPrepareStatement(String sql)。输入参数包含您可以按照描述修改的 sql。

【讨论】:

  • 听起来像是一个解决方案,但似乎我会为 onPrepareStatement 中的 sql 做一个原始字符串替换,这可能不可靠。
  • 是的,这是一个合理的问题。我能想到的唯一可靠且高效的方法是扩展方言并创建一个 StandardSQLFunction 并覆盖 render 方法。在这种方法中,您将获得字符串表示形式,您可以在此处进行相同的修改。请检查“内部”功能是否确实可以这样做。
猜你喜欢
  • 1970-01-01
  • 2011-12-16
  • 2018-02-06
  • 2014-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-24
  • 2011-03-30
相关资源
最近更新 更多