简体   繁体   English

JPA(休眠)onetomany关系

[英]JPA (hibernate) onetomany relation

I am not sure what I am missing to make a bidirectional onetomany relationship (hibernate engine). 我不确定我想要做什么双向onetomany关系(休眠引擎)。 A scaled down version of the domain model: 域模型的缩小版本:

class Person {
@OneToMany(mappedBy="personFrom", cascade = CascadeType.PERSIST)
    public List<Relationship> relationships;
}

class Relationship {
@ManyToOne
  public Person personFrom;

  @ManyToOne
  public Person personTo;
}

Some of the observations: 一些观察结果:
1. with the above mapping, there is no join table created. 1.使用上面的映射,没有创建连接表。
2. When I remove the mappedBy (@OneToMany(cascade = CascadeType.PERSIST) ), the join table is created and i could persist Relationship through Person. 2.当我删除mappedBy(@OneToMany(cascade = CascadeType.PERSIST))时,创建了连接表,我可以通过Person持久保存。 "personFrom" field is empty, but I think that is normal as the relation is maintained through the join table. “personFrom”字段为空,但我认为这是正常的,因为通过连接表维护关系。

I also tried by specifying join column at Relationship, didn't make any difference. 我也尝试通过在关系中指定连接列,没有任何区别。 Any help, highly appreciated. 任何帮助,高度赞赏。 thanks. 谢谢。

Edit:1 编辑:1

As per Dan's comment, if it matters to see the full content of the domain class, I have expanded them below. 根据Dan的评论,如果看到域类的完整内容很重要,我已在下面进行了扩展。

class Relationship extends Model{

  @ManyToOne
  public RelationshipType relationshipType;

  @ManyToOne
  public Person personFrom;

  @ManyToOne
  public Person personTo;

  @ManyToOne
  public Person createdBy;

  @ManyToOne
  public Role roleFrom;

  @ManyToOne
  public Role roleTo;

    @Override
    public String toString() {
        return relationshipType.toString();
    }
}

class Person extends Model {

    public Date dateCreated;

    @Lob
    public String description;

    @OneToMany(cascade = CascadeType.ALL)
    public List<Role> roles;

    @OneToMany(mappedBy="personFrom", cascade = CascadeType.PERSIST)
    public List<Relationship> relationships;
}

Role also related to Person, but I think keeping the personFrom, personTo helps to optimize my queries. 角色也与Person有关,但我认为保持personFrom,personTo有助于优化我的查询。

Role extends Model {

    @ManyToOne
    public RoleType roleType;

    @ManyToOne
    public Person createdBy; 
}

with the above mapping, there is no join table created. 使用上面的映射,没有创建连接表。

A join table is not required for a OneToMany , you'll get foreign key column in the Many side. OneToMany不需要连接表,您将在Many侧获得外键列。 And this is what I get when using your code: 这是我在使用您的代码时得到的:

create table Person (
    id bigint not null,
    primary key (id)
)

create table Relationship (
    id bigint not null,
    personFrom_id bigint,
    personTo_id bigint,
    primary key (id)
)

alter table Relationship 
    add constraint FK499B69164A731563 
    foreign key (personTo_id) 
    references Person

alter table Relationship 
    add constraint FK499B691698EA8314 
    foreign key (personFrom_id) 
    references Person

Which is the expected result (at least for me). 这是预期的结果(至少对我而言)。 Maybe what you actually want is a ManyToMany . 也许你真正想要的是ManyToMany

When I remove the mappedBy (@OneToMany(cascade = CascadeType.PERSIST) ), the join table is created and i could persist Relationship through Person. 当我删除mappedBy(@OneToMany(cascade = CascadeType.PERSIST))时,会创建连接表,我可以通过Person持久保存。 "personFrom" field is empty, but I think that is normal as the relation is maintained through the join table. “personFrom”字段为空,但我认为这是正常的,因为通过连接表维护关系。

I wrote a small unit test using the provided code (with Hibernate's API but this doesn't change anything) and I don't get what the problem is (the session is created before the test method and the method runs inside a transaction): 我使用提供的代码编写了一个小单元测试(使用Hibernate的API,但这并没有改变任何东西),我不知道问题是什么(会话是在测试方法之前创建的,并且方法在事务中运行):

Person p1 = new Person();
Person p2 = new Person();
Relationship r = new Relationship();

// create the personFrom bi-directional association
r.setPersonFrom(p1);
List<Relationship> relationships = new ArrayList<Relationship>();
relationships.add(r);
p1.setRelationships(relationships); // these four lines should be moved to some 
                                    // link management method (see update below).

// create the personTo uni-directional association
r.setPersonTo(p2);

session.persist(p2);
session.persist(p1);

assertNotNull(p2.getId());
assertNotNull(p1.getId());
assertNotNull(r.getId());

The above code results in two insert in the Person table and one insert in the Relationship table (valuing the 3 columns). 上面的代码导致Person表中的两个插入和Relationship表中的一个插入(估计3列)。

As I said, I don't get the problem. 正如我所说,我没有遇到问题。 Maybe you should explain what the expected result is (both the relational model and the queries). 也许您应该解释预期结果是什么(关系模型和查询)。

Update: To be totally clear, when working with bi-directional associations, you have to set both sides of the link and a common pattern is to use defensive link management methods to correctly set both sides of the association. 更新:要完全清楚,在处理双向关联时,您必须设置链接的两侧,并且常见的模式是使用防御性链接管理方法来正确设置关联的两侧。 Something like this: 像这样的东西:

public void addToRelationships(Relationship relationship) {
    if (this.relationships == null) {
       this.relationships = new ArrayList<Relationship>();
    }
    this.relationships.add(relationship);
    relationship.setPersonFrom(this);
}

This is detailed in the section 1.2.6. 这在1.2.6节中详述 Working bi-directional links of the Hibernate documentation. 使用Hibernate文档的双向链接

Did you specify the foreign key column name as the name of your join column? 您是否指定了外键列名称作为连接列的名称? Assuming the foreign key column is named PERSON_ID, the code should look something like this: 假设外键列名为PERSON_ID,代码应如下所示:

class Relationship {
    @ManyToOne
    @JoinColumn(name="PERSON_ID")
    public Person personFrom;
    ...
}

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

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