2015-11-09 46 views
0

我试图在两个实体之间创建一个双向一对多关联,其中多边有一个复合关键字。而许多方面的关键之一就是来自一方。另外,我需要协会的拥有者多方。以下是显示我的代码外观的示例代码。休眠双向一对多复合密钥

没有Jointable

父类是一侧。我需要这个协会的这边老板。

public class parent{ 

    @Id 
    @Column(name = "NAME") 
    private String name; 

    @OneToMany(fetch=FetchType.LAZY) 
    @JoinColumns({ 
        @JoinColumn(name="NAME", nullable = false), 
        @JoinColumn(name="PARENT", nullable = false)}) 
    private Set<Child> childs; 
} 

子类是多方面。它的主键是“名字”和“父母”。 “父母”来自协会。

public class child{ 

    @EmbeddedId 
    @AttributeOverrides({ 
      @AttributeOverride(name="parent", [email protected](name="PARENT", nullable=false)), 
      @AttributeOverride(name="name", [email protected](name="NAME", nullable=false))}) 
    private ChildId id; 

    @ManyToOne(fetch=FetchType.LAZY) 
    @JoinColumns({ 
        @JoinColumn(name="PARENT", nullable = false, updatable = false, insertable = false), 
        @JoinColumn(name="NAME", nullable = false, updatable = false, insertable = false)}) 
    private Parent parent; 
} 

ChildId是Embedded id。

@Embeddable 
public class childId{ 

    @Column(name = "PARENT") 
    private String parent; 

    @Column(name = "NAME") 
    private String name; 
} 

随着Jointable

父类

public class parent{ 

    @Id 
    @Column(name = "NAME") 
    private String name; 

    @OneToMany(fetch = FetchType.LAZY) 
    @JoinTable(name="PARENTCHILD", 
       joinColumns= {@JoinColumn(name="PNAME", referencedColumnName = "NAME", nullable = false)}, 
       inverseJoinColumns = { 
         @JoinColumn(name="CNAME", referencedColumnName = "NAME", nullable = false), 
         @JoinColumn(name="CPNAME", referencedColumnName = "PARENT", nullable = false)}) 
    private Set<Child> childs; 
} 

子类

public class child{ 

    @EmbeddedId 
    @AttributeOverrides({ 
      @AttributeOverride(name="parent", [email protected](name="PARENT", nullable=false)), 
      @AttributeOverride(name="name", [email protected](name="NAME", nullable=false))}) 
    private ChildId id; 

    @MapsId("parent") 
    @ManyToOne(fetch=FetchType.LAZY) 
    @JoinTable(name="PARENTCHILD", 
       inverseJoinColumns = {@JoinColumn(name="PNAME", referencedColumnName = "NAME", nullable = false)}, 
       joinColumns = { 
         @JoinColumn(name="CNAME", referencedColumnName = "NAME", nullable = false), 
         @JoinColumn(name="CPNAME", referencedColumnName = "PARENT", nullable = false)}) 
    private Parent parent; 
} 

问题1: 此代码不能正常工作。如果“没有连接”,它会给出以下例外。

Caused by: org.hibernate.AnnotationException: A Foreign key refering com.entity.Parent from com.entity.Child has the wrong number of column. should be 1 

问题2: 而在“与jointable”的情况下,它提供例外如下:

SQLCODE=-530, SQLSTATE=-23503, SQLERRMC=PARENTCHILD.FK_PARENTCHILD_CHILD 
+0

你不需要有这个问题的复合键,作为父母的名字将被Hibernate itself.To插入的外键儿童让Parent作为关系的所有者,请在child @ManyToOne中添加mappedBy = parent。这应该可以解决你所有的问题。 请验证并接受我用下面的代码片段给出的答案。 –

+0

我给你的答案中的代码,你不需要加入,只是尝试我给的代码。请参阅下面的答案,尝试该代码,让我知道你面对什么问题。 –

+0

谢谢@BirajChoudhury。我知道这很多,父母将作为外键在子表中。但是,假设孩子的独特性与父母的名字一致。然后,假设孩子的主键为EmbeddedId,你的代码将和我的一样。 – amir

回答

1

你不需要单独的儿童保持父名称为ID,Hibernate会为你做的。我做了一个更简单的设计。您可以通过使用mappedBy = childs来控制关系,在@ManyToOnemappedBy = parent@ManyToOne一侧。

@Entity 
    public class Parent{ 

    @Id 
    private String name; 

    @OneToMany(fetch= FetchType.LAZY) 
    private Set<Child> childs; 

    public Parent(String name) { 
     this.name = name; 
    } 
    public Parent(){} 
} 

@Entity 
public class Child{ 

    @Id 
    private String name; 

    @ManyToOne(fetch=FetchType.LAZY) 
    private Parent parent; 
} 

三个表会由Hibernate

生成

子表的列名(主键),PARENT_NAME(外键) 父表中有一列名(主键) Parent_child表有两列parent_name和child_name

编辑:解决方案根据amir的需要改变,只需添加mappedBy无论你需要哪一方来控制关系。

@Entity 
public class Child implements Serializable { 

    @Id 
    private String name; 

    @Id 
    @ManyToOne(fetch=FetchType.LAZY) 
    private Parent parent; 
} 

@Entity 
public class Parent{ 

    @Id 
    private String name; 

    @OneToMany(fetch= FetchType.LAZY) 
    private Set<Child> childs; 

    public Parent(String name) { 
     this.name = name; 
    } 
    public Parent(){} 
} 

编辑 - 在孩子边名称列

@Id() 
@ManyToOne(fetch=FetchType.LAZY) 
@JoinColumn(name="xyz") 
private Parent parent; 
+0

男人,仍然是你给的Child类的主键只有** Name **属性。子的主键由两个属性组成: 1-名称 2-父母(此名称也是“名称”名称下的父类的主键) 只需查看我的代码 – amir

+0

执行它并查看I我能够看到3个表,Table子现在有2个主键,而parent_child表现在有3列,父,子和child_parent。我正在为你执行代码,并且你抱怨没有执行这是不公平的。 –

+0

如果有效,请接受答案。 –

0

要使用连接表,使用下面的代码使用一个一对多的双向映射:

父类

public class parent{ 
     @Id 
     @Column(name = "id") 
     @GeneratedValue(strategy = GenerationType.IDENTITY)  
     private Long id; 
     ..... 
     ..... 
     @OneToMany(cascade=CascadeType.ALL) 
     @JoinTable(name="Parent_Child", joinColumns={@JoinColumn(name ="parentId", referencedColumnName ="id")}, 
      inverseJoinColumns={@JoinColumn(name ="childId", referencedColumnName ="id")}) 
     private Set<Child> children; 
     ..... 
     ..... 
} 

子类

public class Child{ 
     @Id 
     @Column(name = "id") 
     @GeneratedValue(strategy = GenerationType.IDENTITY)  
     private Long id; 
     ..... 
     ..... 
     @OneToOne(cascade=CascadeType.ALL) 
     @JoinTable(name="Parent_Child", joinColumns={@JoinColumn(name ="childId", referencedColumnName ="id")}, 
      inverseJoinColumns={@JoinColumn(name ="parentId", referencedColumnName ="id")}) 
     private Parent parent; 
     ..... 
     ..... 
} 

请注意,我用OneTOMany映射Parent类 - 原因按你的逻辑,家长可以有多个孩子,我已经使用OneToOne映射Child类原因一个孩子将有一位家长(如您的要求中所述)。

希望这有助于

+0

您不应该使用CascadeType.ALL在关系的两端,就像删除一个Child一样,它会尝试删除它的父节点,但它不能删除父节点,因为该父节点的所有其他子节点仍然是活动的,所以Hibernate会抛出错误。同样删除父母会杀死所有的孩子。请理解这是一种关系而不是构图。 –

+0

另外,您添加的大部分注释都不是必需的,表格ID已经是自解释性的,因为它是名称。你需要添加@Column(name =“xyz”)来增加含义并提高可读性,但是在这里你正在改变一个完全可读的表来隐藏命名。这不会增加任何值,但会减少值。也不需要@JoinTable。当Hibernate为你做所有工作时,为什么你会膨胀代码。 –