Jeffrey Blattman
Jeffrey Blattman

Reputation: 22637

JPA OneToMany, always empty

i have a bidirectional, one to many, and many to one relationship. say, a Company has many Persons, and a Persons has one company, so, in company,

@OneToMany(mappedBy = "company", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Collection<Person> persons;

and in Person,

@ManyToOne
@JoinColumn(name="COMPANY_ID")
private Company company;

now, say i have a @PrePersist / @PreUpdate method on Company, where when it is updated, i want to set the same timestamp on all the People ... like,

@PrePersist
@PreUpdate
public void setLastModified() {
    this.lastModified = System.currentTimeMillis();
    if (persons != null) {
        for (Person person : persons) {
            person.setLastModified(this.lastModified);
        }
    }
}

when i debug this, i see that the persons field in Company is always empty. when i look at the type of the persons collection, it's a java.util.Vector. not sure if that's relevant. i expected to see some auto-loading JPA collection type.

what am i doing wrong?

Upvotes: 10

Views: 8803

Answers (5)

BeneStr
BeneStr

Reputation: 347

This is caused by a known bug in Hibernate, see https://hibernate.atlassian.net/browse/HHH-9979.

Unfortunately I am not aware of any workarounds.

Upvotes: 0

user9869932
user9869932

Reputation: 7337

In my case I got this fixed by realizing that I did not need a (Bidirectional) OneToMany - ManyToOne relationship.

For example, in a Unidirectional OneToMany relationship, just write something like:

// Company Class:
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private Set<Person> persons = new HashSet<Person>();

// Person Class:
// - Remove the 3 lines

Check this example: https://github.com/thombergs/code-examples/tree/master/spring-data/spring-data-rest-associations/src/main/java/com/example/demo

If this does not fix your issue, check if you are using Lombok in your Person or Company classes.

If that is the case, add these two annotations in the Company class (vice-versa for the Person class):

@Data
@Entity
@EqualsAndHashCode(exclude = { "persons"}) // This,
@ToString(exclude = { "persons"}) // and this
public class Company implements Serializable {

// ...
private Set<Person> persons = ...
/ ...

Upvotes: 2

James
James

Reputation: 18379

You must set both sides of your relationship. When you create a new Person and set its Company you must also add the Person to the Company's persons (employees?).

Also, you should not change another object in one object's prePersist/Update, you should use its own prePersist/Update event.

See, http://en.wikibooks.org/wiki/Java_Persistence/Relationships#Object_corruption.2C_one_side_of_the_relationship_is_not_updated_after_updating_the_other_side

Upvotes: 2

Zaw Than oo
Zaw Than oo

Reputation: 9935

if you would like to getpersonList in Company, use FetchType.EAGER. In JPA,

@--ToOne    =>  Default :  FetchType.EAGER 
@--ToMany   =>  Default :  FetchType.LAZY

@JoinColumn(name="COMPANY_ID", fetch = FetchType.EAGER)
private Company company;

Upvotes: 0

anergy
anergy

Reputation: 1384

Add fetch = FetchType.Eager to @ManyToOne annotation. You added it on the other side of relationship.

Upvotes: 1

Related Questions