【问题标题】:Hibernate - sqlQuery map redundant records while using JOIN on OneToManyHibernate - 在 OneToMany 上使用 JOIN 时,sqlQuery 映射冗余记录
【发布时间】:2015-11-05 16:53:15
【问题描述】:

我在 2 个实体之间有 @OneToMany 关联(Entity1 To Entity2)。

我的 sqlQueryString 包含以下步骤:

  • select ent1.*, ent2.differ_field from Entity1 as ent1 left outer join Entity2 as ent2 on ent1.item_id = ent2.item_id
  • 添加一些子查询并将结果写入 some_field2、some_field3 等。


执行:

Query sqlQuery = getCurrentSession().createSQLQuery(sqlQueryString)
                 .setResultTransformer(Transformers.aliasToBean(SomeDto.class));

List list = sqlQuery.list();

class SomeDto {
    item_id;
    some_filed1;
    ...
    differ_field;
    ...

}

所以结果是List<SomeDto>

以灰色突出显示的字段是相同的。

所以我想要的是group by,例如item_idList<Object> differFieldList 将作为聚合结果。

class SomeDto {

 ...fields...

 List<Object> differFieldList;

}

或类似Map&lt;SomeDto, List&lt;Object&gt;&gt;

我可以手动映射它,但有一个问题: 当我使用sqlQuery.setFirstResult(offset).setMaxResults(limit) 我检索limit 记录数。但是有多余的行。合并后我的计数实际上减少了。

提前致谢!

【问题讨论】:

  • 完成了所有工作,为什么不全力以赴并使用 JPA?
  • @DuncanKinnear ,我愿意。但是我在 FROM 子句中有一些子查询。当我读到 Hibernate(JPA) 不支持这样的事情
  • @InsFi,它确实支持嵌套查询。
  • @baba ,在FROM 子句中?我只知道WHERESELECT 子句。
  • @InsFI 与 Hibernate,您可以使用 HQL,它是普通 sql 的抽象,它具有与普通 SQL 相同的功能,所以是的,您可以进行内部、外部、左右和上下颠倒加入。

标签: java sql database hibernate orm


【解决方案1】:

从关系数据库的角度来看,重复记录是很自然的。要根据面向对象原则对投影进行分组,可以使用utility like this one

public void visit(T object, EntityContext entityContext) {
    Class<T> clazz = (Class<T>) object.getClass();
    ClassId<T> objectClassId = new ClassId<T>(clazz, object.getId());
    boolean objectVisited = entityContext.isVisited(objectClassId);
    if (!objectVisited) {
        entityContext.visit(objectClassId, object);
    }
    P parent = getParent(object);
    if (parent != null) {
        Class<P> parentClass = (Class<P>) parent.getClass();
        ClassId<P> parentClassId = new ClassId<P>(parentClass, parent.getId());
        if (!entityContext.isVisited(parentClassId)) {
            setChildren(parent);
        }
        List<T> children = getChildren(parent);
        if (!objectVisited) {
            children.add(object);
        }
    }
}

代码可在GitHub获取。

【讨论】:

  • 亲爱的弗拉德,我已经阅读了很多关于 Hibernate 的帖子,但我真的不明白你的回答如何符合我的问题 =) 因为我的愚蠢可能 =)
  • 最简单的方法是 fork 与本文关联的 GitHub 存储库并在调试模式下运行测试。它只是一个简单的子父关联映射实用程序。
【解决方案2】:

如果您想将查询结果存储在此类的集合中:

class SomeDto {
 ...fields...
 List<Object> differFieldList;
}

当使用 sqlQuery.setFirstResult(offset).setMaxResults(n) 时,被限制的记录数基于连接的结果集。合并后的记录数可能比预期的少,而且List中的数据也可能不完整。

要获得预期的数据集,需要将查询分成两部分。

在第一个查询中,您只需从 Entity1 中选择数据

select * from Entity1

Query.setFirstResult(offset).setMaxResults(n) 可以在这里用来限制要返回的记录。如果需要将Entity2中的字段作为该查询的条件,可以使用exists子查询加入Entity2并按Entity2字段进行过滤。

查询返回数据后,您可以提取item_id并将它们放入一个集合中,并使用该集合查询实体2:

select item_id, differ_field from Entity2 where item_id in (:itemid)

Query.setParameterList() 可用于设置从第一个查询返回的项目id集合到第二个查询。然后您需要手动将查询 2 返回的数据映射到查询 1 返回的数据。

这似乎很冗长。如果在两个实体对象之间配置了JPA @OneToMany 映射,并且你的查询可以用HQL 编写(你在评论中说不可能),你可以让Hibernate 自动为你延迟加载Entity2 集合,这种情况下代码可能很多更干净,但在幕后 Hibernate 可能会在延迟加载位于 Many 端的实体时向 DB 生成更多查询请求。

【讨论】:

  • 是的,我几天前也是这样做的,但没有偷懒。懒惰不适合我的情况。我的问题是:Hibernate 是否足够聪明,可以像在 HQL 中那样在 1 个查询中执行此类操作。如果否,您的答案是最接近的
猜你喜欢
  • 2021-10-16
  • 1970-01-01
  • 1970-01-01
  • 2018-11-22
  • 1970-01-01
  • 1970-01-01
  • 2014-04-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多