使用hibernate实现联合查询有哪些替代方法?我知道hibernate目前不支持联合查询,现在我看到建立联合的唯一方法就是使用视图表。

另一种选择是使用普通的jdbc,但是这样我会放弃所有的示例/条件查询好东西,以及hibernate对表/列执行的hibernate映射验证。

有帮助吗?

解决方案

使用VIEW。可以使用实体名称将相同的类映射到不同的表/视图,因此您甚至不会有太多重复。在那里,做到这一点,工作正常。

普通JDBC有另一个隐藏的问题:它不知道Hibernate会话缓存,所以如果某些东西被缓存到事务结束并且没有从Hibernate会话中刷新,那么JDBC查询将找不到它。可能有时候非常令人费解。

其他提示

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

e.g。而不是不工作

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);

通常两个简单的查询比一个复杂的查询更好。

编辑:

举个例子,这是从subselect解决方案得到的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。row不使用任何索引并考虑200k +行。坏!执行此查询需要0.7秒,因为两个子查询都在毫秒内。

我必须同意弗拉基米尔。我也考虑过在HQL中使用UNION而无法找到解决方法。奇怪的是,我可以找到(在Hibernate常见问题解答中)UNION不受支持,与UNION标记为“已修复”的错误报告,人们的新闻组称这些声明将在UNION被截断,而其他人报道的新闻组也有效精细... 经过一天的捣乱,我最终将我的HQL移植回纯SQL,但在数据库中的View中进行它将是一个不错的选择。在我的例子中,查询的一部分是动态生成的,所以我不得不在代码中构建SQL。

我在HQL中使用union有一个针对一个关键场景(我为此奋斗了很多)的解决方案。

<强> e.g。而不是不工作: -

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

OR

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中做什么 - <!> gt;

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();

然后你可以添加两个列表 - <!> gt;

l1.addAll(l2);

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

也许我有一个更直接的问题需要解决。我的'例如'是在JPA中,Hibernate是JPA提供者。

我将三个选择(在第二种情况下为两个)分成多个选择并合并自己返回的集合,有效地替换了'union all'。

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

对我来说,好消息是我只是在调查联盟以解决在Oracle数据库中使用'或'时的性能问题。

Patrick发布的解决方案(以编程方式使用集合结果)虽然丑陋(特别是因为我想做结果分页)对我来说已经足够了。

搜索结果 正如帕特里克所说,从每个 SELECT 中追加 LIST 将是一个好主意,但要记住它的作用类似于 UNION ALL 。要避免这种副作用,只需控制对象是否已添加到最终集合中。如果不是,则添加它。
您需要注意的其他事项是,如果每个 SELECT 中有 JOIN ,则结果将是对象数组列表( List&lt; Objetc []&gt; )因此您必须迭代它以仅保留您需要的对象。 搜索结果 希望它有效。

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

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

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

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

正如你在这里看到的那样,命名查询开始看起来很像一个联合语句:

@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);
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top