2012-03-31 65 views
4

應堅持@OneToMany關係,我有兩個實體:與@JoinColumn和@MapKeyColumn

@Entity 
Article { 
    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private Long id; 

    @OneToMany(fetch = FetchType.EAGER, cascade=CascadeType.ALL) 
    @JoinColumn(name="embed_id", referencedColumnName="id") 
    @MapKeyColumn(name = "language") 
    @MapKeyEnumerated(EnumType.ORDINAL) 
    private Map<Language, Locale> locales; 

    Article() { 
     locales.put(Language.CS, new Locale()); 
     locales.put(Language.EN, new Locale()); 
    } 
} 

@Entity 
Locale { 
    @Id 
    private Long embed_id; 

    @Id 
    private Language language; 

    @Column(length = 256) 
    private String name; 
} 

由於構造函數中,我可以保證,一旦一個Article被實例化,二Locales(含CascadeType.ALL)與它相關聯。

問題是當我試圖堅持這樣的實體 - 我越來越:

javax.persistence.EntityExistsException: 
a different object with the same identifier value was already associated 
     with the session: org...Locale#[email protected] 

的問題是,無論是embed_id,也不language已從第二十持續時賦值和Hibernate不會將它們後關聯堅持條款。如何才能做到這一點?

編輯1:

我檢查,當embed_idlanguage手動設置,一切正常。我只需要告訴Hibernate,根據@OneToMany關係設置@JoinColumn和@MapKeyColumn的值。

編輯2:

與MapKeyColumn這個問題有一個簡單的解決方案:

public void addLocale(Language l, Locale locale) { 
     locale.setLanguage(l); 
     this.locales.put(l); 
} 

但是,我還是不能告訴休眠到Locale.embed_id從Article.id關聯。

編輯3:

我可以看到正確生成物品的ID,但隨後沒有放在區域:

DEBUG org.hibernate.event.internal.AbstractSaveEventListener - 
    Generated identifier: 87, using strategy: org.hibernate.id.SequenceGenerator 
DEBUG org.hibernate.event.internal.AbstractSaveEventListener - 
    Generated identifier: component[language,embedId]{language=0, embedId=null}, using strategy: org.hibernate.id.CompositeNestedGeneratedValueGenerator 
DEBUG org.hibernate.event.internal.AbstractSaveEventListener - 
    Generated identifier: component[language,embedId]{language=1, embedId=null}, using strategy: org.hibernate.id.CompositeNestedGeneratedValueGenerator 

回答

0

我終於找到了!訣竅是創建文章Setter和添加訪問ID如下:

@Id 
@Getter 
@Access(AccessType.PROPERTY) 
@GeneratedValue(strategy = GenerationType.AUTO) 
private Long id; 

public void setId(Long id) { 
    this.id = id; 
    this.getLocale(Language.CS).setEmbedId(id); 
    this.getLocale(Language.EN).setEmbedId(id); 
} 
3

我想這個問題是,你想要堅持兩個空的區域設置。而且,由於您不使用生成器來生成id字段,因此語言環境具有相同的(空)主鍵,因此無法保留。

+0

我知道,但我怎麼能告訴休眠他們與關鍵的地圖?它不僅是語言 - 因爲當我手動設置它時,我得到:'embed_id'列中的空值違反了非空約束;' – 2012-03-31 08:48:18

+0

但是'embed_id'不一定是唯一的(因爲您將它與'language'實現獨特性)。一個非唯一的密鑰可能不是「map」的(唯一)密鑰? – 2012-03-31 08:54:18

+0

它與語言結合是獨一無二的。主鍵是'embed_id,language'組合。 – 2012-03-31 09:01:49