如何使用父实体的组合键执行JPA @OneToMany单向映射?

时间:2016-04-01 23:37:19

标签: java hibernate jpa groovy

目前这些只是查询操作,如果您“获取”父项,您希望获取所有子项。遗留数据库(DB2)是遗留数据库(DB2),其中父表中有三个字段是其复合PK。子表具有这三个字段,另外还有一个作为其复合PK。

无需双向。只需要让孩子和父母一起。

@Entity @IdClass(ParentId.class)
class Parent {
    @Id int someId
    @Id int someCode
    @Id Date someDate

    @OneToMany(fetch = FetchType.EAGER, ???)
    ???
    List<Child> children
}

class ParentId implements Serializable {
    int someId
    int someCode
    Date someDate
}

@Entity @IdClass(ChildId.class)
class Child {
    @Id int someId
    @Id int someCode
    @Id Date someDate
    @Id String childValue
    ...
}

class ChildId implements Serializable {
    int someId
    int someCode
    Date someDate
    String childValue
}

ChildId类非常类似于父类和另一个字段。

我是否需要切换到@Embeddable和@EmbeddableId等?无论如何,任何人都有想法如何使这项工作?我见过的例子比较简单,似乎对我不起作用。

我可以更改父类和子类,但不能更改表及其当前的复合PK。

3 个答案:

答案 0 :(得分:1)

您可以使用@IdClass@EmbeddedId。无论哪种方式,您使用的是“衍生身份”。以下是使用@IdClass

的可能解决方案
@Entity
@IdClass(ParentId.class)
public class Parent {
    @Id int someId;
    @Id int someCode;
    @Id Date someDate;

    @OneToMany(fetch = FetchType.EAGER, mappedBy = "parent")
    List<Child> children;
}

public class ParentId implements Serializable {
    int someId;
    int someCode;
    Date someDate;
    ...
}

@Entity
@IdClass(ChildId.class)
public class Child {
    @Id
    @ManyToOne
    @JoinColumns({
        @JoinColumn(name="PARENT_ID", referencedColumnName="someId"),
        @JoinColumn(name="PARENT_CODE", referencedColumnName="someCode"),
        @JoinColumn(name="PARENT_DATE", referencedColumnName="someDate") 
    })
    Parent parent;
    @Id String childValue;
    ...
}

public class ChildId implements Serializable {
    ParentId parent; // matches name of attribute and type of Parent Id class
    String childValue;
}

衍生身份在JPA 2.1规范第2.4.1节中讨论。

答案 1 :(得分:1)

您可以使用单向映射继续@IdClass。为此,您可以在@JoinColumns({...)}类的cascade字段中添加List<Child> childrenParent属性,如下所示:

@Entity @IdClass(ParentId.class)
class Parent {
    @Id int someId;
    @Id int someCode;
    @Id Date someDate;

    @OneToMany(fetch = FetchType.EAGER, cascade=CascadeType.ALL)
    @JoinColumns({
        @JoinColumn(name="someId", referencedColumnName="someId"),
        @JoinColumn(name="someCode", referencedColumnName="someCode"),
        @JoinColumn(name="someDate", referencedColumnName="someDate") 
})    
    List<CKChild> children = new ArrayList<>();
}
class ParentId implements Serializable {
    int someId;
    int someCode;
    Date someDate;
}

@Entity @IdClass(ChildId.class)
class Child {
    @Id int someId;
    @Id int someCode;
    @Id Date someDate;
    @Id String childValue;
}

class ChildId implements Serializable {
    int someId;
    int someCode;
    Date someDate;
    String childValue;
}

但是,更好的想法是使用双向映射mappedBy一起使用,如Brian的回答所示。

从DML语句中执行是有效的。使用Unidirectional,您会在保存children时看到List<Child>中每个Parent实体的一个额外更新语句。使用Bidirectional时,不会产生额外的更新语句。

<强>更新

我要检索的测试代码:

session = openSession();
tx = session.beginTransaction();
System.out.println(session.createQuery("select p from Parent p").list());
tx.commit();

并给我关注

Hibernate: select ckparent0_.someCode as someCode1_1_, ckparent0_.someDate as someDate2_1_, ckparent0_.someId as someId3_1_ from Parent ckparent0_
Hibernate: select children0_.someCode as someCode2_0_0_, children0_.someDate as someDate3_0_0_, children0_.someId as someId4_0_0_, children0_.childValue as childVal1_0_0_, children0_.childValue as childVal1_0_1_, children0_.someCode as someCode2_0_1_, children0_.someDate as someDate3_0_1_, children0_.someId as someId4_0_1_ from Child children0_ where children0_.someCode=? and children0_.someDate=? and children0_.someId=?
Hibernate: select children0_.someCode as someCode2_0_0_, children0_.someDate as someDate3_0_0_, children0_.someId as someId4_0_0_, children0_.childValue as childVal1_0_0_, children0_.childValue as childVal1_0_1_, children0_.someCode as someCode2_0_1_, children0_.someDate as someDate3_0_1_, children0_.someId as someId4_0_1_ from Child children0_ where children0_.someCode=? and children0_.someDate=? and children0_.someId=?
**Retrieved :** [org.hibernate.bugs.Parent@1e17ad20, org.hibernate.bugs.Parent@7111ca49]

使用以下DDL

Hibernate: create table Child (childValue varchar(255) not null, someCode integer not null, someDate timestamp not null, someId integer not null, primary key (childValue, someCode, someDate, someId))
Hibernate: create table Parent (someCode integer not null, someDate timestamp not null, someId integer not null, primary key (someCode, someDate, someId))
Hibernate: alter table Child add constraint FKl06s6kkl5xx2s82tlbsh160vo foreign key (someCode, someDate, someId) references Parent

答案 2 :(得分:0)

首先,这是Groovy,上面的代码有点暗示,但我没有明确提到。这需要注释使用括号'[]'而不是花括号'{}'来指定像@JoinColumn这样的数组属性。

除此之外,它比我想象的要简单。对于具有相同字段的单向关系,我不需要指定实际的列名称或引用的列名称。只是常见的字段名称。

我也切换到Set并按照在数据库中指定键的顺序放置@JoinColumns。最后两件事可能无关紧要。

@Entity @IdClass(ParentId.class)
class Parent {
    @Id int someCode
    @Id Date someDate
    @Id int someId

    @OneToMany(fetch = FetchType.EAGER)
    @JoinColumns([@JoinColumn(name = "someCode"),
        @JoinColumn(name = "someDate"),
        @JoinColumn(name = "someId")])
    Set<Child> children
}