2012-06-01 38 views
20

我有兩個實體,我想通過多列加入。這些列由兩個實體共享的@Embeddable對象共享。在下面的示例中,Foo可以只有一個Bar,但Bar可以有多個Foo(其中AnEmbeddableObjectBar的唯一密鑰)。這裏有一個例子:多列加入Hibernate/JPA註釋

@Entity 
@Table(name = "foo") 
public class Foo { 
    @Id 
    @Column(name = "id") 
    @GeneratedValue(generator = "seqGen") 
    @SequenceGenerator(name = "seqGen", sequenceName = "FOO_ID_SEQ", allocationSize = 1) 
    private Long id; 
    @Embedded 
    private AnEmbeddableObject anEmbeddableObject; 
    @ManyToOne(targetEntity = Bar.class, fetch = FetchType.LAZY) 
    @JoinColumns({ 
     @JoinColumn(name = "column_1", referencedColumnName = "column_1"), 
     @JoinColumn(name = "column_2", referencedColumnName = "column_2"), 
     @JoinColumn(name = "column_3", referencedColumnName = "column_3"), 
     @JoinColumn(name = "column_4", referencedColumnName = "column_4") 
    }) 
    private Bar bar; 

    // ... rest of class 
} 

,酒吧類:

@Entity 
@Table(name = "bar") 
public class Bar { 
    @Id 
    @Column(name = "id") 
    @GeneratedValue(generator = "seqGen") 
    @SequenceGenerator(name = "seqGen", sequenceName = "BAR_ID_SEQ", allocationSize = 1) 
    private Long id; 
    @Embedded 
    private AnEmbeddableObject anEmbeddableObject; 

    // ... rest of class 
} 

最後AnEmbeddedObject類:

@Embeddable 
public class AnEmbeddedObject { 
    @Column(name = "column_1") 
    private Long column1; 
    @Column(name = "column_2") 
    private Long column2; 
    @Column(name = "column_3") 
    private Long column3; 
    @Column(name = "column_4") 
    private Long column4; 

    // ... rest of class 
} 

顯然架構標準化很差,這是一個限制,即AnEmbeddedObject「每個表中都重複了這些字段。

我的問題是,當我嘗試啓動休眠,我收到此錯誤:

org.hibernate.AnnotationException: referencedColumnNames(column_1, column_2, column_3, column_4) of Foo.bar referencing Bar not mapped to a single property 

我已經試過這標誌着JoinColumns不是插入和更新,但沒有運氣。有沒有一種方法來表達這與Hibernate/JPA註釋?

+0

如果您從「Foo」中刪除可嵌入的內容,該怎麼辦? – siebz0r

回答

9

如果這不起作用,我就沒有想法。通過這種方式,您可以在兩個表中獲得4列(因爲Bar擁有它們,Foo使用它們來引用Bar)以及兩個實體中生成的ID。 4列的集合在Bar中必須是唯一的,所以多對一關係不會成爲多對多關係。

@Embeddable 
public class AnEmbeddedObject 
{ 
    @Column(name = "column_1") 
    private Long column1; 
    @Column(name = "column_2") 
    private Long column2; 
    @Column(name = "column_3") 
    private Long column3; 
    @Column(name = "column_4") 
    private Long column4; 
} 

@Entity 
public class Foo 
{ 
    @Id 
    @Column(name = "id") 
    @GeneratedValue(generator = "seqGen") 
    @SequenceGenerator(name = "seqGen", sequenceName = "FOO_ID_SEQ", allocationSize = 1) 
    private Long id; 
    @ManyToOne(fetch = FetchType.LAZY) 
    @JoinColumns({ 
     @JoinColumn(name = "column_1", referencedColumnName = "column_1"), 
     @JoinColumn(name = "column_2", referencedColumnName = "column_2"), 
     @JoinColumn(name = "column_3", referencedColumnName = "column_3"), 
     @JoinColumn(name = "column_4", referencedColumnName = "column_4") 
    }) 
    private Bar bar; 
} 

@Entity 
@Table(uniqueConstraints = @UniqueConstraint(columnNames = { 
    "column_1", 
    "column_2", 
    "column_3", 
    "column_4" 
})) 
public class Bar 
{ 
    @Id 
    @Column(name = "id") 
    @GeneratedValue(generator = "seqGen") 
    @SequenceGenerator(name = "seqGen", sequenceName = "BAR_ID_SEQ", allocationSize = 1) 
    private Long id; 
    @Embedded 
    private AnEmbeddedObject anEmbeddedObject; 
} 
+0

這就是摩擦,兩個對象中必須存在「AnEmbeddedObject」。由於性能原因,生成的ID更可取。 – bowsie

+0

那麼這4列加上生成的關鍵映射吧?這非常糟糕。如果你的解決方案是爲'Bar'生成一個代理鍵,並且不要在'Foo'外鍵中創建列,那麼你必須自己在'Foo'中設置列。如果我是對的,我可以調整我的答案。 ;-) – siebz0r

+0

@bowsie我修改了我的答案,所以'Foo'和'Bar'都有4列,'Bar'在'Foo'中用它的ID引用。 – siebz0r

4

Hibernate不會讓你輕鬆地做你正在做的事情。從Hibernate documentation

請注意,將referencedColumnName用於非主鍵列時,關聯的類必須是Serializable。 另請注意,referencedColumnName與非主鍵列必須映射到具有單列的屬性(其他情況可能不起作用)。(強調)

所以,如果你不願意讓AnEmbeddableObject標識符的酒吧則Hibernate不會懶惰,自動檢索酒吧爲您服務。當然,您仍然可以使用HQL編寫在AnEmbeddableObject上加入的查詢,但如果堅持對Bar使用多列非主鍵,則會失去自動提取和生命週期維護。

+0

我會說它值得一試,理論上使用多個指向一個唯一約束的外鍵應該是可能的。如果這不是運氣不好的話。 +1這可能是答案。 – siebz0r

+0

@ siebz0r,OP已經拍攝並獲得了幾乎完全正確的錯誤信息,我期望這個錯誤條件:「referencedColumnNames ... ***未映射到單個屬性***」。它應該說「沒有映射到只有一列的財產」,但它是大致相同的事情。 –

+0

我猜這是遊戲,然後;-) – siebz0r

10

這對我有用。在我的情況下,2個表foo和boo必須基於3個不同的列加入。請注意,在我的情況下,3個常見列不是主鍵

即,基於3個不同列的一對一映射

@Entity 
@Table(name = "foo") 
public class foo implements Serializable 
{ 
    @Column(name="foocol1") 
    private String foocol1; 
    //add getter setter 
    @Column(name="foocol2") 
    private String foocol2; 
    //add getter setter 
    @Column(name="foocol3") 
    private String foocol3; 
    //add getter setter 
    private Boo boo; 
    private int id; 
    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    @Column(name = "brsitem_id", updatable = false) 
    public int getId() 
    { 
     return this.id; 
    } 
    public void setId(int id) 
    { 
     this.id = id; 
    } 
    @OneToOne 
    @JoinColumns(
    { 
     @JoinColumn(updatable=false,insertable=false, name="foocol1", referencedColumnName="boocol1"), 
     @JoinColumn(updatable=false,insertable=false, name="foocol2", referencedColumnName="boocol2"), 
     @JoinColumn(updatable=false,insertable=false, name="foocol3", referencedColumnName="boocol3") 
    } 
    ) 
    public Boo getBoo() 
    { 
     return boo; 
    } 
    public void setBoo(Boo boo) 
    { 
     this.boo = boo; 
    } 
} 





@Entity 
@Table(name = "boo") 
public class Boo implements Serializable 
{ 
    private int id; 
    @Column(name="boocol1") 
    private String boocol1; 
    //add getter setter 
    @Column(name="boocol2") 
    private String boocol2; 
    //add getter setter 
    @Column(name="boocol3") 
    private String boocol3; 
    //add getter setter 
    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    @Column(name = "item_id", updatable = false) 
    public int getId() 
    { 
     return id; 
    } 
    public void setId(int id) 
    { 
     this.id = id; 
    } 
}