2014-11-24 83 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孩子和父母之間。

請讓我知道。

相關問題