2014-11-24 105 views
9

我试图坚持使用JPA1与Hibernate实现两个不同的实体。 该代码,如下图所示:非空属性引用空值或瞬态值为持久值

父实体类

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

    {...} 
    private Child child; 

    @ManyToOne(fetch = FetchType.LAZY) 
    @JoinColumn(name = "child_id", nullable = "false") 
    public Child getChild() { 
     return child; 
    } 

    public void setChild(Child child) { 
     this.child = child; 
} 

儿童实体类

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

    private Integer id; 

    @Id 
    @Column(name = "child_id") 
    public Integer getId() { 
     return id; 
    } 

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

测试用例

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration("classpath:META-INF/application.xml") 
@Transactional 
public class ParentTest extends TestCase { 

    @PersistenceContext 
    private EntityManager entityManager; 

    @Test 
    public void testSave() { 
     Child child = new Child(); 
     child.setId(1); 

     Parent parent = new Parent(); 
     parent.setChild(child); 

     entityManager.persist(parent.getChild()); 
     entityManager.persist(parent); // throws the exception 
    } 
} 

实体管理和交易应用。 xml

<tx:annotation-driven transaction-manager="transactionManager" /> 

<jee:jndi-lookup id="dataSource" jndi-name="java:/jdbc/myds" expected-type="javax.sql.DataSource" /> 

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
    <property name="packagesToScan" value="com.mypackage" /> 
    <property name="dataSource" ref="dataSource" /> 
    <property name="jpaVendorAdapter"› 
     <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/> 
    </property> 
    <property name="jpaProperties"> 
     <props> 
      <prop key="hibernate.dialect>org.hibernate.dialect.Oracle10gDialect</prop> 
     </props> 
    </property> 
</bean> 

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> 
    <property name="entityManagerFactory" ref="entityManagerFactory" /> 
</bean> 

当试图插入父对象时,即使child在此操作之前被创建并持久化,hibernate也会抛出PropertyValueException异常,并指出child为null或transient。奇怪的是,这只在单元测试中失败,而在真正的应用程序中,插入了一个预先插入的子项,这与预期一致。

PS: 我很清楚我可以映射孩子级联坚持,但这不是这里的主意。我只是想检查这两个工作是否独立。

+0

什么类型是EntityManager?我找不到任何对insert()方法的引用。 – 2014-11-25 10:00:33

+0

我认为这可能与Junit方法中的事务处理有关。只有当孩子已经在数据库中时(提交之后)才能插入父代。这将解释为什么它在你的“真实”应用程序上工作而不是在这里。你能分享你的application.xml文件吗? – santedicola 2014-11-25 12:08:06

+0

@PredragMaric我的不好。我正在使用坚持的方法。固定在帖子上。 – renke 2014-11-25 15:49:48

回答

2

除了有一个FK父对子问题,持续顺序是什么导致你的问题。

您的问题是related to flushing。仅仅因为你指示Hibernate坚持一个对象,并不意味着它会自动满足你的请求。持久请求仅在冲洗时才会实现动作队列。所以你的第二个坚持简单地找到父实体没有一个实际的“坚持”的孩子。

你可以简单的解决您的代码如下:

Child child = new Child(); 
    child.setId(1); 

    entityManager.persist(parent.getChild()); 
    entityManager.flush(); 

    Parent parent = new Parent(); 
    parent.setChild(child); 
    entityManager.persist(parent); 
    entityManager.flush; 
+0

在这种情况下,孩子有一个手动设置的ID,因此不需要刷新数据库即可使用并在上下文中持久化。尽管如此,在每次坚持之后我都尝试冲洗实体经理,但仍然没有运气。 – renke 2014-11-28 16:17:03

7

这里的问题是,你是坚持与设定值父表。 当它持续存在时,它需要子表ID,它必须已经被持久化,因为它是一个外键,因此它是一个非空属性引用一个空值。

@Test 
    public void testSave() { 
     Child child = new Child(); 
     child.setId(1); 
     entityManager.persist(child); 

     Parent parent = new Parent(); 
     parent.setChild(child); 

     entityManager.persist(parent); 
    } 

尝试使用此方法,然后再救孩子父母的.else改变映射

+0

在提供的代码片段中,我坚持孩子在父母之前,唯一的区别是您在孩子被保留后设置孩子。这与我所做的没有任何不同,因为我保留对孩子的引用,并且关系映射不是双向的。 – renke 2014-11-28 13:07:53

0

一些字段被设置为not-null="true"你saveing到数据库之前提供该值。 对于父表和子表的所有字段设置所有NOT NULL字段与适当的值

+0

......这正是我正在做的。 – renke 2014-11-28 16:17:49

0

先给@ManyToOne(fetch = FetchType.LAZY,cascade=PERSIST, mappedBy="parent")public Child getChild(),坚持只母object.Both将持续。

1

试试这个:您正在使用@ManyToOne告诉我,你有一个孩子的对象不止一个家长

@ManyToOne(fetch = FetchType.LAZY,optional=false) 
@JoinColun(name = "child_id", nullable = "false") 
public Child getChild() { 
    return child; 
} 
2

的第一件事就是父母,我想这是不是这样的。

根据你的类结构,我可以理解你有父对象和子对象之间的OneToOne映射。

关于这个例外,是不是有一个原因,你没有使用Parent和Child之间的级联来自动处理保存,更新和删除映射?如果你还没有想过这个问题比你可以通过设置下面的配置这里指定试试看:Example Parent/Child - Hibernate

cascade = {CascadeType.ALL} 

虽然我会建议从多对一的映射更改为OneToOne孩子和父母之间。

请让我知道。

相关问题