简体   繁体   English

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

[英]How can I do a JPA @OneToMany unidirectional mapping with the parent entity's composite key?

Currently these are only query operations where if you "get" the parent, you want to eager fetch all the children. 当前,这些只是查询操作,如果您“获取”父级,则希望获取所有子级。 It is legacy a legacy database (DB2) where there are three fields in the parent table that are its composite PK. 它是遗留的遗留数据库(DB2),其中父表中的三个字段是其组合PK。 The child table has those three fields and one more as its composite PK. 子表具有这三个字段,另外一个作为其组合PK。

No need for bidirectional. 无需双向。 Just need to get the children along with parent. 只需要让孩子和父母一起。

@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 class is pretty much like the parent one plus another field. ChildId类非常类似于父类和另一个字段。

Do I need to switch to @Embeddable and @EmbeddableId etc.? 我需要切换到@Embeddable和@EmbeddableId等吗? Regardless, anyone have ideas how to make this work? 无论如何,任何人都有如何使这项工作的想法? I've seen examples that are more simplistic and don't seem to work for me. 我看过的例子更加简单化,似乎对我不起作用。

I can change the Parent and Child classes but not the tables and their current composite PKs. 我可以更改Parent和Child类,但不能更改表及其当前的组合PK。

You can use either an @IdClass or @EmbeddedId . 您可以使用@IdClass@EmbeddedId Either way, you are using "Derived identities". 无论哪种方式,您都在使用“派生身份”。 Here is a possible solution using @IdClass : 这是使用@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;
}

Derived identities are discussed in the JPA 2.1 spec, section 2.4.1. JPA 2.1规范的第2.4.1节中讨论了派生身份。

You can continue with @IdClass with the Unidirectional mapping . 您可以继续使用@IdClass进行单向映射 For that you can add @JoinColumns({...)} along with cascade attribute on the List<Child> children field on the Parent class, as below: 为此,您可以在Parent类的List<Child> children字段上添加@JoinColumns({...)}以及cascade属性,如下所示:

@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;
}

But then, the better idea would be to go with Bidirection mapping with mappedBy as indicated in the Brian's answer. 但是,更好的主意是按照Brian的回答中的说明,使用带有mappedBy 双向映射

It is efficient from DML statement that get executed. 从执行的DML语句开始,它是有效的。 With Unidirectional you will see one extra update statement for each children entity in the List<Child> while saving the Parent . 随着Unidirectional你会看到每一个额外的更新语句children实体 List<Child> ,同时节省了Parent And with Bidirectional it doesn't result in this extra update statement. 而且使用Bidirectional时,不会导致此额外的更新语句。

UPDATE: 更新:

My test code to retrieve: 我的测试代码检索:

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

and gives me following 并给我以下

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]

With the following DDLs 使用以下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

So first of all, this is Groovy which the above code kinda implies but I didn't explicitly mention. 因此,首先,这是Groovy,上面的代码有点暗示,但我没有明确提及。 This requires the annotations to use brackets '[]' instead of curly braces '{}' to specify array properies like @JoinColumn. 这要求注释使用方括号“ []”而不是大括号“ {}”来指定数组属性,例如@JoinColumn。

Beyond that it was simpler than I thought. 除此之外,它比我想象的要简单。 For the unidirectional relationship with same fields, I didn't need to specify actual column names or referenced column names. 对于具有相同字段的单向关系,我不需要指定实际的列名或引用的列名。 Just the field names that were common. 只是常见的字段名称。

I also switched to a Set and put the @JoinColumns in the order that the keys were specified in the database. 我还切换到Set并按在数据库中指定键的顺序放置@JoinColumns。 These last two things probably don't matter though. 最后两件事可能并不重要。

@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
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM