简体   繁体   English

JPQL / HQL:选择或失败

[英]JPQL/HQL: select with OR fails

I have some problems with my query, but don't know where exactly. 我的查询有一些问题,但不知道确切的位置。
This query return, for example, 3 Change objects: 该查询返回例如3个Change对象:

select c from Change c where c.entityOne.serial = 'TEST3'

This query return, for example, 2 Change objects: 该查询返回例如2个Change对象:

select c from Change c where c.entityTwo.serial = 'TEST3'

But this query return 0, when I expect something between 3 and 5. 但是当我期望3到5之间的值时,此查询返回0。

select c from Change c where (c.entityOne.serial = 'TEST3' or c.entityTwo.serial = 'TEST3')

Where am I wrong? 我哪里错了? If you need some more code, please, ask. 如果您需要更多代码,请询问。

TEST TO REPRODUCE: 进行测试:
Sorry for a lot of code, but it is required to reproduce this issue. 很抱歉,有很多代码,但是重现此问题是必需的。

Change.java Change.java

@Entity
public class Change {
    private long id;
    private EntityOne entityOne;
    private EntityTwo entityTwo;

    @Id
    @GeneratedValue
    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    @ManyToOne
    public EntityOne getEntityOne() {
        return entityOne;
    }

    public void setEntityOne(EntityOne entityOne) {
        this.entityOne = entityOne;
    }

    @ManyToOne
    public EntityTwo getEntityTwo() {
        return entityTwo;
    }

    public void setEntityTwo(EntityTwo entityTwo) {
        this.entityTwo = entityTwo;
    }
}

EntityOne.java and EntityTwo.java (simply rename the class) EntityOne.java和EntityTwo.java(仅重命名该类)

@Entity
public class EntityOne {
    private long id;
    private String serial;

    @Id
    @GeneratedValue
    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getSerial() {
        return serial;
    }

    public void setSerial(String serial) {
        this.serial = serial;
    }
}

Test.java - run it. Test.java-运行它。

public class Test {
    private static EntityManagerFactory buildFactory() {
        try {
            return Persistence.createEntityManagerFactory("migration-tool");
        } catch (Throwable ex) {
            ex.printStackTrace();
        }
        return null;
    }

    public static void main(String[] args) {
        EntityManagerFactory emf = buildFactory();
        EntityManager em = emf.createEntityManager();
        Query q = em.createQuery("select c from Change c where (c.entityOne.serial = 'TEST3' or c.entityTwo.serial = 'TEST3')");
        List<Change> changeRecords =  q.getResultList();
        System.out.println(changeRecords.size());
        emf.close();
    }
}

persistence.xml persistence.xml中

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0">
    <persistence-unit name="migration-tool" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <class>test.Change</class>
        <class>test.EntityOne</class>
        <class>test.EntityTwo</class>
        <properties>
            <property name="hibernate.search.autoregister_listeners" value="false"/>
            <property name="hibernate.cache.region.factory_class"
                      value="net.sf.ehcache.hibernate.EhCacheRegionFactory"/>
            <property name="hibernate.cache.use_query_cache" value="true"/>
            <property name="hibernate.connection.url" value="jdbc:postgresql://127.0.0.1:5434/test"/>
            <property name="hibernate.connection.username" value="postgres"/>
            <property name="hibernate.connection.password" value="123456"/>
            <property name="hibernate.connection.driver_class" value="org.postgresql.Driver"/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
        </properties>
    </persistence-unit>
</persistence>

Dependencies in pom.xml pom.xml中的依赖项

<dependency>
    <groupId>postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>9.1-901.jdbc4</version>
</dependency>
<dependency>
    <groupId>javax.persistence</groupId>
    <artifactId>persistence-api</artifactId>
    <version>1.0</version>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-annotations</artifactId>
    <version>3.4.0.GA</version>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-entitymanager</artifactId>
    <version>3.4.0.GA</version>
</dependency>
<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache-core</artifactId>
    <version>2.6.0</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.4.2</version>
</dependency>

And SQL script to fill in the data. 和SQL脚本一起填写数据。

CREATE TABLE entityone
(
  id bigint NOT NULL,
  serial character varying(255),
  PRIMARY KEY (id)
);

CREATE TABLE entitytwo
(
  id bigint NOT NULL,
  serial character varying(255),
  PRIMARY KEY (id)
);

CREATE TABLE change
(
  id bigint NOT NULL,
  entityone_id bigint,
  entitytwo_id bigint,
  PRIMARY KEY (id),
  FOREIGN KEY (entityone_id) REFERENCES entityone(id),
  FOREIGN KEY (entitytwo_id) REFERENCES entitytwo(id)
);

insert into entityone values (1, 'TEST3');
insert into entityone values (2, 'TEST1');
insert into entityone values (3, 'TEST2');
insert into entityone values (4, 'TEST3');

insert into entitytwo values (1, 'TEST3');
insert into entitytwo values (2, 'TEST3');
insert into entitytwo values (3, 'TEST4');
insert into entitytwo values (4, 'TEST3');

insert into change values (1, 1, NULL);
insert into change values (2, 2, NULL);
insert into change values (3, 3, NULL);
insert into change values (4, 4, NULL);
insert into change values (5, NULL, 1);
insert into change values (6, NULL, 2);
insert into change values (7, NULL, 3);
insert into change values (8, NULL, 4);

Writing up an answer from comments: 用评论写出答案:

The problem are the NULL values. 问题是NULL值。 Chapter 16.4 of Hibernate documentation (v 4.3) state: Hibernate文档(v 4.3)的第16.4章规定:

16.4. 16.4。 Forms of join syntax 连接语法的形式

HQL supports two forms of association joining: implicit and explicit. HQL支持两种形式的关联连接:隐式和显式。

The queries shown in the previous section all use the explicit form, that is, where the join keyword is explicitly used in the from clause. 上一节中显示的查询全部使用显式形式,即在from子句中显式使用join关键字。 This is the recommended form. 这是推荐的形式。

The implicit form does not use the join keyword. 隐式形式不使用join关键字。 Instead, the associations are "dereferenced" using dot-notation. 而是使用点符号“取消引用”关联。 implicit joins can appear in any of the HQL clauses. 隐式联接可以出现在任何HQL子句中。 implicit join result in inner joins in the resulting SQL statement. 隐式联接会在结果SQL语句中进行内部联接

from Cat as cat where cat.mate.name like '%s%' 来自Cat,作为cat,其中cat.mate.name类似于'%s%'

I have bolded out the most relevant part. 我已经加粗了最相关的部分。 What this says is that your dot notation will be unrolled into an inner join, and since the key is null - your entities will not appear in the join. 这说明您的点表示法将被展开到内部联接中,并且由于键为空-您的实体将不会出现在联接中。
The SQL that Hibernate executed also shows this (the below is beautified for the sake of readability): Hibernate执行的SQL也显示了这一点(为了便于阅读,下面将其美化):

select change  
from Change change, EntityOne entityone, EntityTwo entitytwo
where 
change.entityOne_id=entityone.id and
change.entityTwo_id=entitytwo.id and  
(
    ((change.entityOne_id is not null) and entityone.serial='TEST3') or 
    ((change.entityTwo_id is not null) and entitytwo.serial='TEST3')
)

Unfortunately, the dot notation will not allow you to get the desired result. 不幸的是,点符号不能使您获得理想的结果。 You would have to create the joins yourself, as in the above docs, chapter 16.3. 您必须自己创建联接,如上面的文档第16.3章中所述。 Example: 例:

SELECT c
FROM Change AS c
    LEFT JOIN Change.entityOne as entityOne
    LEFT JOIN Change.entityTwo as entityTwo
WHERE
    entityOne.serial = "TEST3" OR entityTwo.serial = "TEST3"

NOTE: I do not have a working setup with Hibernate, you may have to add extra null checks to the above 注意:我没有Hibernate的有效安装程序,您可能必须在上面添加额外的null检查

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM