开发者

JPA (hibernate) onetomany relation

I am not sure what I am missing to make a bidirectional onetomany relationship (hibernate engine). 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.

2. When I remove the mappedBy (@OneToMany(cascade = CascadeType.PERSIST) ), the join table is created and i could persist Relationship through Person. "personFrom" field is empty, but I think that is normal as the relation is maintained through the join table.

I also tried 开发者_JAVA百科by specifying join column at Relationship, didn't make any difference. Any help, highly appreciated. thanks.

Edit:1

As per Dan's comment, if it matters to see the full content of the domain class, I have expanded them below.

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.

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. 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.

When I remove the mappedBy (@OneToMany(cascade = CascadeType.PERSIST) ), the join table is created and i could persist Relationship through Person. "personFrom" field is empty, but I think that is normal as the relation is maintained through the join table.

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):

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).

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. Working bi-directional links of the Hibernate documentation.


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:

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜