0

I'm quite new to Hibernate, I've set-up @OneToMany bidirectional relationships between parent and child objects and expect when I persist everything in the DB, set parent object to child object (because child object is the owner of the relationship) and when I fetch parent object with the ORM I expect to fetch a child object as well but in return I see zero child objects.

As far as I understood from what I've already read on the internet, when I persist child object as the owner of the relationships with the parent intact ORM is supposed to do the magic of wiring two objects according to predefined relationship mapping. Is this information correct?

@Entity
@Table(name = "stream")
@SequenceGenerator(name = "sequence", sequenceName = "stream_id", allocationSize = 1)
public class StreamEntity extends EntityWithId {

    // @MappedSuperclass with ID 

    @Column(name = "request_id")
    @OneToMany(
            mappedBy = "streamEntity",
            fetch = FetchType.LAZY
    )
    private List<RequestEntity> requestEntities = new ArrayList<>();

    // getters setters
}

@Entity
@Table(name = "request")
@SequenceGenerator(name = "sequence", sequenceName = "request_id", allocationSize = 1, initialValue = 1)
public class RequestEntity extends EntityWithId {

    // @MappedSuperclass with ID 

    @JoinColumn(name = "stream_id")
    @ManyToOne(fetch = FetchType.LAZY)
    private StreamEntity streamEntity;

    // getters setters
}

Some tests:

@Test
public void createStreamWithSeveralStreamTargetsAndDeleteStream() {
    List<StreamEntity> streamEntities = createStream(1); // stream object is persisted here

    List<RequestEntity> requestEntitySave = createRequest(1, streamEntityCheck);
    assertEquals(1, requestEntitySave.size()); // request entity is persisted with the stream object into the database

    List<StreamEntity> streamEntities = streamDao.findAll();
    assertEquals(1, streamEntities.size());
    StreamEntity streamEntity2 = streamEntities.get(0);
    streamEntity2.getRequestEntities(); - this collection shows 0
}

What am I missing?

Update: As @Alan Hay suggested I've added a @Persistent context into my test now it looks like this :

@PersistenceContext
    private EntityManager em;


@Test
    public void createStreamWithSeveralStreamTargetsAndDeleteStream() {
        List<StreamEntity> streamEntities = createStream(1); // stream object is persisted here

        List<RequestEntity> requestEntitySave = createRequest(1, streamEntityCheck);
        assertEquals(1, requestEntitySave.size()); // request entity is persisted with the stream object into the database

        em.clear();

List<RequestEntity> requestEntities = requestDao.findAll();
        assertEquals(1, requestEntities.size()); // retirns zero objects

        List<StreamEntity> streamEntities = streamDao.findAll();
        assertEquals(1, streamEntities.size());
        StreamEntity streamEntity2 = streamEntities.get(0);
        streamEntity2.getRequestEntities();// this collection shows 0
    }

After I made this I'm getting zero objects on the requestDao.findAll(); step. I've committed these changes in the previous step why can't I fetch this entity?

Miklosh
  • 139
  • 2
  • 10
  • take a look here: [Difference between FetchType LAZY and EAGER in Java Persistence API?](https://stackoverflow.com/questions/2990799/difference-between-fetchtype-lazy-and-eager-in-java-persistence-api) – Kaan Sep 26 '19 at 15:08
  • Thanks for the answer, I've already read about the difference between fetch types, as far as I understood with the FetchType.LAZY it should return at least the proxy object but it returns nothing. – Miklosh Sep 26 '19 at 15:20

1 Answers1

1

Due to the concept of the 1st level cache, the initial object you created and saved and the one you have loaded are the same instance. As you did not add the created request entity to the in-memory model but merely persisted it to the database the relationship does not exist in the in-memory model.

To get the desired result you need to clear the persistence context between saving and reloading.

@Test
    public void createStreamWithSeveralStreamTargetsAndDeleteStream() {
        List<StreamEntity> streamEntities = createStream(1); 

        List<RequestEntity> requestEntitySave = createRequest(1, streamEntityCheck);
        assertEquals(1, requestEntitySave.size()); 

        //you need to clear the persistence context here
        //now a db query should execute.
        //Inject the entitymanager to your test @PersistenceContext EntityManager em;
        em.clear();

        List<StreamEntity> streamEntities = streamDao.findAll();
        assertEquals(1, streamEntities.size());
        StreamEntity streamEntity2 = streamEntities.get(0);
        streamEntity2.getRequestEntities(); - this collection shows 0

   }
Alan Hay
  • 22,665
  • 4
  • 56
  • 110
  • Thank you for the answer, I have few more questions thou. I'm using spring-data with this fancy obscured CRUD methods, I thought that they are doing all this stuff with clearing the context etc out of the box, is it correct? Do I need to perform any additional configuration to spring data in order for it to work as I expect it to work? – Miklosh Sep 26 '19 at 15:32
  • First level cache is managed by hibernate and cannot be bypassed. Normally you would want it anyway. It is your responsibility to ensure the consistency of the in memory model. – Alan Hay Sep 26 '19 at 15:51