Hibernate中的NullPointerException用于fetch = EAGER

时间:2016-08-11 12:54:07

标签: java hibernate

当我将@OneToMany字段的fetch属性设置为FetchType.EAGER时,我一直在尝试解决Hibernate类中的NullPointerException问题。我认为我做错了什么但我看不清楚,有人可以帮忙吗?

这是错误:

Caused by: java.lang.NullPointerException
    at org.hibernate.engine.internal.StatefulPersistenceContext.getLoadedCollectionOwnerOrNull(StatefulPersistenceContext.java:780)
    at org.hibernate.event.spi.AbstractCollectionEvent.getLoadedOwnerOrNull(AbstractCollectionEvent.java:58)
    at org.hibernate.event.spi.InitializeCollectionEvent.<init>(InitializeCollectionEvent.java:22)
    at org.hibernate.internal.SessionImpl.initializeCollection(SessionImpl.java:2002)
    at org.hibernate.collection.internal.AbstractPersistentCollection$4.doWork(AbstractPersistentCollection.java:562)
    at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:246)
    at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:558)
    at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:131)
    at org.hibernate.collection.internal.PersistentSet.toArray(PersistentSet.java:170)
    at testhib.entities.Parent.$$_hibernate_write_children(Parent.java)
    ... 64 more

这是我构建的测试用例:

数据库

CREATE TABLE `test`.`parent` (
  `parent_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `parent_version` int(10) unsigned NOT NULL DEFAULT '1',
  `parent_name` varchar(64) DEFAULT NULL,
  PRIMARY KEY (`parent_id`)
);

CREATE TABLE `test`.`child` (
  `child_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `child_version` int(10) unsigned NOT NULL DEFAULT '1',
  `child_name` varchar(64) DEFAULT NULL,
  `child_parent` int(10) unsigned NOT NULL,
  PRIMARY KEY (`child_id`),
  KEY `fk_child_1_idx` (`child_parent`),
  CONSTRAINT `fk_child_1` FOREIGN KEY (`child_parent`) REFERENCES `parent` (`parent_id`)
);

INSERT INTO `test`.`parent`
(`parent_id`, `parent_name`)
VALUES
(1, 'Homer');

INSERT INTO `test`.`child`
(`child_id`, `child_name`, `child_parent`)
VALUES
(1, 'Bart', 1),
(2, 'Lisa', 1),
(3, 'Maggie', 1);

实体

package testhib.entities;

import java.io.Serializable;
import java.util.Set;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

import static javax.persistence.FetchType.EAGER;

@Entity
@Table(name = "parent")
public class Parent implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "parent_id")
    private Integer parentId;

    @Basic(optional = false)
    @Column(name = "parent_version")
    private int parentVersion;

    @Column(name = "parent_name")
    private String parentName;

    @OneToMany(mappedBy = "parent", fetch = EAGER)
    private Set<Child> children;

    public Integer getParentId() {
        return parentId;
    }

    public void setParentId(Integer parentId) {
        this.parentId = parentId;
    }

    public int getParentVersion() {
        return parentVersion;
    }

    public void setParentVersion(int parentVersion) {
        this.parentVersion = parentVersion;
    }

    public String getParentName() {
        return parentName;
    }

    public void setParentName(String parentName) {
        this.parentName = parentName;
    }

    public Set<Child> getChildren() {
        return children;
    }

    public void setChildren(Set<Child> children) {
        this.children = children;
    }
}

package testhib.entities;

import java.io.Serializable;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@Table(name = "child")
public class Child implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "child_id")
    private Integer childId;

    @Basic(optional = false)
    @Column(name = "child_version")
    private int childVersion;

    @Column(name = "child_name")
    private String childName;

    @JoinColumn(name = "child_parent", referencedColumnName = "parent_id")
    @ManyToOne
    private Parent parent;

    public Integer getChildId() {
        return childId;
    }

    public void setChildId(Integer childId) {
        this.childId = childId;
    }

    public int getChildVersion() {
        return childVersion;
    }

    public void setChildVersion(int childVersion) {
        this.childVersion = childVersion;
    }

    public String getChildName() {
        return childName;
    }

    public void setChildName(String childName) {
        this.childName = childName;
    }

    public Parent getParent() {
        return parent;
    }

    public void setParent(Parent parent) {
        this.parent = parent;
    }
}

测试

package testhib.test;

import java.util.HashSet;
import java.util.Set;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import testhib.entities.Parent;

import static org.junit.Assert.assertThat;
import static org.hamcrest.Matchers.containsInAnyOrder;

public class Tests {

    private static EntityManagerFactory emf;
    private EntityManager em;

    public Tests() {
    }

    @BeforeClass
    public static void setUpClass() {

        emf = Persistence.createEntityManagerFactory("test-hib");
    }

    @AfterClass
    public static void tearDownClass() {

        emf.close();
    }

    @Before
    public void setUp() {

        em = emf.createEntityManager();

        em.getTransaction().begin();
    }

    @After
    public void tearDown() {

        em.getTransaction().commit();

        em.close();
    }

    @Test
    public void canRead() {

        Parent p = em.find(Parent.class, 1);

        Set<String> names = new HashSet<>();

        p.getChildren().stream().forEach((c) -> {

            names.add(c.getChildName());
        });

        assertThat(names, containsInAnyOrder("Bart", "Lisa", "Maggie"));
    }
}

peristence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
  <persistence-unit name="test-hib" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
    <class>testhib.entities.Parent</class>
    <class>testhib.entities.Child</class>
    <properties>
      <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/test"/>
      <property name="javax.persistence.jdbc.user" value="test"/>
      <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
      <property name="javax.persistence.jdbc.password" value="password"/>
    </properties>
  </persistence-unit>
</persistence>

POM

<?xml version="1.0" encoding="UTF-8"?>
<project
        xmlns="http://maven.apache.org/POM/4.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>uk.co.discoverdorset</groupId>
    <artifactId>test-hib</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>test-hib</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>5.1.0.Final</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.39</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-all</artifactId>
            <version>1.3</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-web-api</artifactId>
            <version>7.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.hibernate.orm.tooling</groupId>
                <artifactId>hibernate-enhance-maven-plugin</artifactId>
                <version>5.1.0.Final</version>
                <executions>
                    <execution>
                        <configuration>
                            <failOnError>true</failOnError>
                            <enableLazyInitialization>true</enableLazyInitialization>
                            <enableDirtyTracking>true</enableDirtyTracking>
                            <enableAssociationManagement>true</enableAssociationManagement>
                            <enableExtendedEnhancement>false</enableExtendedEnhancement>
                        </configuration>
                        <goals>
                            <goal>enhance</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

如果我从Parent实体中注释掉“fetch = EAGER”,那么测试会毫无障碍地运行。

有什么想法吗?

0 个答案:

没有答案