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;
...
}
精彩评论