Reputation: 58742
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 by specifying join column at Relationship, didn't make any difference. Any help, highly appreciated. thanks.
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;
}
Upvotes: 3
Views: 2702
Reputation: 570585
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.
Upvotes: 2
Reputation: 4486
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;
...
}
Upvotes: 0