2011-04-29 60 views
0

我使用JPA-> Hibernate。 PlayFramework。我想要有關係。一對多和重複條目

Category - 1:n -> Tag 

每個類別都可以有很多標籤,但標籤不知道它。

所以,我這樣做:

@Entity 
public class Category ... { 
    @OneToMany 
    public List<Tag> tags = new LinkedList<Tag>(); 
} 

我有測試:

@Test 公共無效playWithTags(){

Tag tag1 = new Tag("tag1").save(); // managed by playframework 

    Category cat1 = new Category("cat1"); 
    cat1.tags.add(tag1); 
    cat1.save(); 

    // check if tag1 and cat1 were saved 
    assertEquals(1, Tag.count()); 
    assertEquals(1, Category.count()); 

    Category cat2 = new Category("cat2"); 
    cat2.tags.add(tag1); 
    cat2.save(); 

} 

結果是:

16:18:01,555 ERROR ~ Duplicate entry '1' for key 'tags_id' 
16:18:01,555 ERROR ~ Could not synchronize database state with session 
org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update 
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96) 
    at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelp 
.... 
java:908) 
    at java.lang.Thread.run(Thread.java:619) 
Caused by: java.sql.BatchUpdateException: Duplicate entry '1' for key 'tags_id' 
    at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:2020) 

似乎cat2.save()嘗試做多,那麼它應該

如果如果用合併(),而不是保存()它的工作原理好:

cat2.merge(); 

但爲什麼呢?

回答

5

我已經解決了這個問題。問題在於,我沒有使用這個註釋。所以我只是將@OneToMany改爲@ManyToMany,並且沒有任何限制。

但是如果談論OneToMany,那麼似乎在數據庫級別上有一個獨特的限制,它阻止了我們將不唯一的值賦給tags_id。因此,我們不能將相同的標籤放在一個類別中。即它希望一個類別的許多標籤,但如果標籤已經'使用' - 沒辦法..我試圖把唯一= true/false @JoinTable - > @JoinColumn - 但它沒有幫助。對我來說,這仍然很奇怪,但至少目前的問題已經解決。

5

你在混淆兩個概念:主要的密鑰和國外的鍵。

只能有一個PK,但FK只是意味着「在其他表格中必須有這個ID的元素」。 FK不限制唯一性。

[編輯]你的問題是你是混合實體。你是如何獲得由save()返回的tag1

該實體必須是您從Hibernate獲得的實體,而不是從new得到的結果。即使它看起來瘋了,你必須在save()做到這一點:

session.save(tag); 
return session.load(tag.getId()); 

這樣,你得到的是Hibernate管理的實體。只有當實體由Hibernate管理時,Hibernate才知道何時必須保存實體以及何時已經保存實體。

所以當你在上面的例子中做cat2.tags.add(tag1);時,Hibernate認爲「哦,我對這個標籤一無所知,它必須是一個新標籤」。

並嘗試再次保存標記。

+0

是的。但我的錯誤是:無法添加或更新子行:外鍵約束失敗..... FOREIGN KEY('tags_id')引用'標記('id')' – ses 2011-04-29 13:07:39

+0

錯誤表示標記未寫入TAB表格。添加標籤後您是否正確提交?如果您運行普通的SQL查詢,是否可以從數據庫中讀取標籤? – 2011-04-29 16:06:08

+0

Tag tag1 =新的Tag(「tag1」)。save();這由PlayFramework管理。當它在這裏返回tag1時,它已經由hibernate管理 - 它具有id,與session等綁定在一起。不,他不認爲'這一定是新的'。不應該 - 因爲tag1保存並通過play的save()返回。 – ses 2011-04-29 21:08:06