Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return an empty list on @OneToMany that is indeed 0 to many (nullable)

I have a FK that recursively points to the very same entity, but it can't be nullable

Person entity:

@OneToMany(fetch = FetchType.LAZY)
@JoinColumn(name = "personId", referencedColumnName = "managerId", updatable = false, insertable = false, nullable = true)
private List<Person> managers;

But this is returning null instead of an empty list when the join is null. The problem is that I am not sure it's an error, or a design fault. While debugging, child person shows managers as a persistent bag, but orphan persons have no empty persistent bag but a null value.

But in this question, a user affirms the list should always be initialized: To initialize or not initialize JPA relationship mappings?

Just for your info, theres no LazyLoadingExceptions as all the code is within a @Transactional

In this other question (JPA OneToMany - Collection is null) there's an explanation about JPA using noargs constructor and setting fields directly from db, so I am wondering if the problem is that JPA sets the list to null because the fb returns the join column as null. If that were the case, would it be a way to tell JPA to send an empty list instead of null?

The code for fetching is a test:

@Test
@Transactional
public void fetchManagersOfCEO(){
    Person person = this.personRepository.findOne(1L);
    assertThat(result.getManagers().size()).isEqualTo(0);
}

This return expected managers when the id is the one of an employee with managers above

P.S> After a lot of debugging, the problem is that JPA is setting the collection to null, no "COLLECTION NOT NULL" ObjectMarker, and empty CollectionReferenceInitializers

I don't like it but the only way I found to work out the issue is:

public List<Person> getManagers(){
    return Optional.ofNullable(this.managers).orElseGet(ArrayList::new);
}
like image 837
Whimusical Avatar asked Oct 31 '25 12:10

Whimusical


2 Answers

Just do this:

@OneToMany(fetch = FetchType.LAZY)
@JoinColumn(name = "personId", referencedColumnName = "managerId", updatable = false, insertable = false, nullable = true)
private List<Person> managers = new ArrayList<>();
like image 129
Tobb Avatar answered Nov 03 '25 02:11

Tobb


Let's say we have entity A that has one to many entity B.

You can then replicate your problem by:

  • Creating A with no (null) list of B.
  • Persisting A.
  • Fetching A in the same transaction.

This is because Hibernate refers to the same object in a single transaction and the object has null as a list of B.

However, if you are in two separate transactions or if you manually clear the session (SessionFactory.clear or EntityManager.clear) then the list should properly be initialized with an empty persistent bag.

like image 42
Mariano LEANCE Avatar answered Nov 03 '25 02:11

Mariano LEANCE