我试图使用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 } }
实体管理器和application.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>
当尝试插入父对象时,hibernate会抛出一个PropertyValueException异常,即孩子在此操作之前创建并持久化,即为null或transient.奇怪的是,这只是在单元测试中失败,在实际应用中,使用预插入的小孩,这与预期一样工作.
PS:
我很清楚,我可以映射孩子与级联坚持,但这不是这里的想法.我只想检查这两个是否独立工作.
解决方法
这里的问题是您正在使用设置的值来保持父表.
当它持续时,它需要必须保持的子表id,因为它是一个外键,因此它是一个not null属性引用一个空值.
当它持续时,它需要必须保持的子表id,因为它是一个外键,因此它是一个not null属性引用一个空值.
@Test public void testSave() { Child child = new Child(); child.setId(1); entityManager.persist(child); Parent parent = new Parent(); parent.setChild(child); entityManager.persist(parent); }
尝试这样来保存孩子,然后保存父进程