JPA OneToMany, always empty
Asked Answered
R

5

10

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?

Revenant answered 26/2, 2011 at 0:28 Comment(0)
B
2

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

Bret answered 16/10, 2012 at 13:47 Comment(1)
I was going to add my own hack with a rudimentary version of what this link specifies, but I had no idea it was actually an approach suggested by experts.Roane
F
1

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

Foster answered 28/2, 2011 at 12:52 Comment(1)
thanks. i haven't got a chance to verify this yet, but i will update this question when i do.Revenant
Z
1

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 = ...
/ ...
Zajac answered 23/5, 2019 at 3:31 Comment(0)
B
0

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;
Bilbrey answered 27/9, 2012 at 15:13 Comment(0)
F
0

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.

Flyblown answered 16/12, 2020 at 14:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.