Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Weird behavour when using bidirectional oneToMany in combination with jpa postload #3750

Open
JaimePolidura opened this issue Jan 24, 2025 · 4 comments
Assignees
Labels
status: feedback-provided Feedback has been provided status: waiting-for-triage An issue we've not yet triaged

Comments

@JaimePolidura
Copy link

Hello,

I',m unsure if this is project is the correct place to report the following behavour I've observed, please let me know if I should report it to another github project.

With the latest spring boot 3.4.x version, I have observed the following problem in my springboot project that uses spring data jpa to persist againsts postgres database. I have created a small springboot project to reproduce this bug github project

  • I have a parent entity with a oneToMany relationship to a child entity.
  • In the child entity I have a bidirectional manyToOne relationship to the parent.
  • Aditionally in the parent I have a jpa @PostLoad annotation where I just sort the list of children by an integer field.
  • I have added a spring boot test to persist a parent whith three children, and then load all children from database.
  • For your convenience, the pom.xml includes docker-maven-plugin to start postgres via docker, please use the following command: mvn docker:start -Pdocker

The test throws an exception because of during the postload in the list of children the first child's fields are null, interestingly other children have fields with values as expected, please see screenshot:

Image

I have added a feature branch in my project revert-to-old-springboot where I use spring boot 3.3.x instead and the test is successful and the bug does not appear.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jan 24, 2025
@mp911de mp911de self-assigned this Jan 27, 2025
@mp911de
Copy link
Member

mp911de commented Jan 31, 2025

Have you verified the behavior is different when using Hibernate through EntityManager?

@mp911de mp911de added the status: waiting-for-feedback We need additional information before we can continue label Jan 31, 2025
@JaimePolidura
Copy link
Author

JaimePolidura commented Jan 31, 2025

I have tried to use EntityManager and the bug still appears. Here is the code that I have used:

@SpringBootTest
class HibernatePostloadBugExperimentApplicationTests {
  @Autowired
  private EntityManager entityManager;

  @BeforeEach
  @Transactional
  public void setup() {
    entityManager.createQuery("DELETE FROM Parent").executeUpdate();
    entityManager.createQuery("DELETE FROM Child").executeUpdate();
  }

  @Test
  @Transactional
  void contextLoads() {
    Parent parent = new Parent();
    entityManager.persist(parent);

    entityManager.persist(new Child(1, parent));
    entityManager.persist(new Child(2, parent));
    entityManager.persist(new Child(3, parent));

    entityManager.flush();
    entityManager.clear();

    List<Child> children = entityManager.createQuery("SELECT c FROM Child c").getResultList();
    assertEquals(3, children.size());
  }
}

Link to the code

Let me know if that is what you meant.
Thanks!

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Jan 31, 2025
@mp911de
Copy link
Member

mp911de commented Jan 31, 2025

Yes, that's what I was looking for. Please note that your code is slightly different (posting the reproducer from your GitHub repo):

  @Test
  void contextLoads() {
    Parent parent = new Parent();
    parentRepository.save(parent);
    childRepository.save(new Child(1, parent));
    childRepository.save(new Child(2, parent));
    childRepository.save(new Child(3, parent));

    List<Child> children = childRepository.findAll();

    assertEquals(3, children.size());
  }

All save run in their own transaction while the code ab uses a single surrounding @Transactional. To make the code truly comparable, each entityManager.persist(…) would either need to be ran in TransactionTemplate.execute(…) or your contextLoads test method must be @Transactional.

@JaimePolidura
Copy link
Author

JaimePolidura commented Jan 31, 2025

Oops, you are right, sorry. I have updated it, and the bug still appears.

Here is the code:

@SpringBootTest
class HibernatePostloadBugExperimentApplicationTests {
  @Autowired
  private TransactionTemplate transactions;
  @Autowired
  private EntityManager entityManager;

  @BeforeEach
  public void setup() {
    transactions.executeWithoutResult(s -> {
      entityManager.createQuery("DELETE FROM Child").executeUpdate();
      entityManager.createQuery("DELETE FROM Parent").executeUpdate();
    });
  }

  @Test
  void contextLoads() {
    Parent parent = new Parent();
    transactions.executeWithoutResult(s -> entityManager.persist(parent));
    
    transactions.executeWithoutResult(s -> entityManager.persist(new Child(1, parent)));
    transactions.executeWithoutResult(s -> entityManager.persist(new Child(2, parent)));
    transactions.executeWithoutResult(s -> entityManager.persist(new Child(3, parent)));

    List<Child> children = transactions.execute(t ->
        entityManager.createQuery("SELECT c FROM Child c").getResultList());

    assertEquals(3, children.size());
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: feedback-provided Feedback has been provided status: waiting-for-triage An issue we've not yet triaged
Projects
None yet
Development

No branches or pull requests

3 participants