java-休眠联盟替代品

使用冬眠实现联合查询,我有什么选择? 我知道休眠状态目前不支持联合查询,现在我看到的建立联合的唯一方法是使用视图表。

另一个选择是使用普通的jdbc,但是这样一来,我将失去所有示例/条件查询功能,以及hibernate对表/列执行的hibernate映射验证。

Miguel Ping asked 2019-11-15T16:54:53Z
9个解决方案
68 votes

您可以使用id in (select id from ...) or id in (select id from ...)

例如 而不是不工作

from Person p where p.name="Joe"
union
from Person p join p.children c where c.name="Joe"

你可以做

from Person p 
  where p.id in (select p1.id from Person p1 where p1.name="Joe") 
    or p.id in (select p2.id from Person p2 join p2.children c where c.name="Joe");

不过,至少使用MySQL,以后会遇到性能问题。 有时在两个查询中进行穷人联接比较容易:

// use set for uniqueness
Set<Person> people = new HashSet<Person>((List<Person>) query1.list());
people.addAll((List<Person>) query2.list());
return new ArrayList<Person>(people);

进行两个简单的查询通常比处理一个复杂的查询要好。

编辑:

举个例子,这是子选择解决方案的结果MySQL查询的EXPLAIN输出:

mysql> explain 
  select p.* from PERSON p 
    where p.id in (select p1.id from PERSON p1 where p1.name = "Joe") 
      or p.id in (select p2.id from PERSON p2 
        join CHILDREN c on p2.id = c.parent where c.name="Joe") \G
*************************** 1. row ***************************
           id: 1
  select_type: PRIMARY
        table: a
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 247554
        Extra: Using where
*************************** 2. row ***************************
           id: 3
  select_type: DEPENDENT SUBQUERY
        table: NULL
         type: NULL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: NULL
        Extra: Impossible WHERE noticed after reading const tables
*************************** 3. row ***************************
           id: 2
  select_type: DEPENDENT SUBQUERY
        table: a1
         type: unique_subquery
possible_keys: PRIMARY,name,sortname
          key: PRIMARY
      key_len: 4
          ref: func
         rows: 1
        Extra: Using where
3 rows in set (0.00 sec)

最重要的是,1.行不使用任何索引,而是考虑200k +行。 坏! 该查询的执行时间为0.7s,其中两个子查询都以毫秒为单位。

sfussenegger answered 2019-11-15T16:56:36Z
29 votes

使用VIEW。 可以使用实体名称将相同的类映射到不同的表/视图,因此您甚至不需要太多重复。 在那里,这样做就可以了。

普通的JDBC还有一个隐藏的问题:它不知道Hibernate会话缓存,因此,如果在事务结束之前缓存了某些内容,并且没有从Hibernate会话中清除该内容,则JDBC查询将找不到它。 有时候可能会很令人困惑。

Vladimir Dyuzhev answered 2019-11-15T16:55:23Z
6 votes

我必须同意弗拉基米尔。 我也考虑在HQL中使用UNION,但找不到解决方法。 奇怪的是,我发现(在Hibernate FAQ中)不支持UNION,与UNION有关的错误报告标记为“已修复”,新闻组的人说该声明将在UNION处被截断,其他新闻组的人则说它有效 精细...经过一天的摸索,我最终将HQL移植回普通的SQL,但是在数据库的View中进行操作将是一个不错的选择。 就我而言,部分查询是动态生成的,因此我不得不在代码中构建SQL。

CodingWithSpike answered 2019-11-15T16:57:02Z
4 votes

对于HQL中的联合,我有一个关键场景(为此我苦苦挣扎)的解决方案。

例如 而不是不工作:-

select i , j from A a  , (select i , j from B union select i , j from C) d where a.i = d.i 

要么

select i , j from A a  JOIN (select i , j from B union select i , j from C) d on a.i = d.i 

您可以在Hibernate HQL中执行->

Query q1 =session.createQuery(select i , j from A a JOIN B b on a.i = b.i)
List l1 = q1.list();

Query q2 = session.createQuery(select i , j from A a JOIN C b on a.i = b.i)
List l2 = q2.list();

然后你可以添加两个列表->

l1.addAll(l2);
Vijay Gupta answered 2019-11-15T16:57:55Z
3 votes

视图是一种更好的方法,但是由于hql通常返回List或Set ...,因此可以执行list_1.addAll(list_2)。 完全比工会糟透了,但应该可以。

answered 2019-11-15T16:58:20Z
2 votes

也许我还有一个更直接的问题要解决。 我的“例如”是在JPA中,而Hibernate是JPA提供程序。

我将三个选择(在第二种情况下为两个)拆分为多个选择,然后合并了自己返回的集合,有效地替换了“全部合并”。

Walt answered 2019-11-15T16:58:56Z
0 votes

我也经历过这种痛苦-如果查询是动态生成的(例如Hibernate Criteria),那么我找不到可行的方法。

对我来说,好消息是,我只是在研究工会以在Oracle数据库中使用“或”时解决性能问题。

帕特里克(Patrick)发布的解决方案(使用一组程序以编程方式组合结果)非常丑陋(特别是因为我也想进行结果分页)对我来说足够了。

Daniel Alexiuc answered 2019-11-15T16:59:40Z
0 votes



正如Patrick所说,从每个SELECT附加LIST是一个好主意,但请记住,它的行为就像UNION ALL。 为了避免这种副作用,只需控制对象是否已经添加到最终集合中。 如果否,则添加它。
您还需要注意的另一件事是,如果每个SELECT中都有任何JOIN,则结果将是对象数组的列表(List<Objetc[]>),因此您必须对其进行迭代以仅保留所需的对象。

希望它能工作。

Arash moradabadi answered 2019-11-15T17:00:18Z
0 votes

这是一个特例,但可能会启发您创建自己的作品。 此处的目标是计算记录满足特定条件的两个不同表中的记录总数。 我相信这项技术适用于需要从多个表/源中汇总数据的任何情况。

我有一些特殊的中间类设置,因此调用命名查询的代码简短而甜美,但是您可以使用通常与命名查询结合使用的任何方法来执行查询。

QueryParms parms=new QueryParms();
parms.put("PROCDATE",PROCDATE);

Long pixelAll = ((SourceCount)Fetch.row("PIXEL_ALL",parms,logger)).getCOUNT();

正如您在此处看到的那样,命名查询开始看起来非常像union语句:

@Entity
@NamedQueries({
        @NamedQuery(
            name  ="PIXEL_ALL",
            query = "" +
                    "  SELECT new SourceCount(" +
                    "     (select count(a) from PIXEL_LOG_CURR1 a " +
                    "       where to_char(a.TIMESTAMP, 'YYYYMMDD') = :PROCDATE " +
                    "     )," +
                    "     (select count(b) from PIXEL_LOG_CURR2 b" +
                    "       where to_char(b.TIMESTAMP, 'YYYYMMDD') = :PROCDATE " +
                    "     )" +
                    ") from Dual1" +
                    ""
    )
})

public class SourceCount {
    @Id
    private Long   COUNT;

    public SourceCount(Long COUNT1, Long COUNT2) {
        this.COUNT = COUNT1+COUNT2;
    }

    public Long getCOUNT() {
        return COUNT;
    }

    public void setCOUNT(Long COUNT) {
        this.COUNT = COUNT;
    }
}

这里的魔术的一部分是创建一个虚拟表并将一个记录插入到其中。 在我的情况下,我将其命名为dual1,因为我的数据库是Oracle,但是我认为所谓的哑表并不重要。

@Entity
@Table(name="DUAL1")
public class Dual1 {
    @Id
    Long ID;
}

不要忘了插入您的虚拟记录:

SQL> insert into dual1 values (1);
wryan answered 2019-11-15T17:01:15Z
translate from https://stackoverflow.com:/questions/201023/hibernate-union-alternatives