0

I want to populate my object hierarchy eagerly. The problem is that at some point Hibernate stops from fetching; it leaves relation fields (lists) unpopulated.

The hierarchy is (some code is ommited like id's, getters, this part seems to be fine, hopefully):

public class User {
    private Container container;

    @OneToOne(fetch = FetchType.EAGER)
    public Container getContainer() {
        return container;
    }
}


public class Container {
    private List<Backpack> backpacks;
    private List<Item> items;

    @OneToMany(fetch = FetchType.EAGER, mappedBy="container")
    @Fetch(FetchMode.SELECT)
    private List<Item> getItems() {
        return items;
    }


    @OneToMany(fetch = FetchType.EAGER, mappedBy="container")
    @Fetch(FetchMode.SELECT)
    private List<Backpack> getBackpacks() {
        return backpacks;
    }
}


public class Backpack {
    ...
    private Container container;            /* Unidirectional relationship - ID of container which contains this backpack */
    private Container backpackContainer;    /* Unidirectional relationship - ID of container which represents backpack's storge */
    ...

    @NotNull
    @ManyToOne(fetch = FetchType.EAGER)
    @Fetch(FetchMode.SELECT)
    public Container getContainer() {
        return container;
    }


    @OneToOne(fetch = FetchType.EAGER)
    @Fetch(FetchMode.SELECT)
    public Container getBackpackContainer() {
        return backpackContainer;
    }
}

And the result:

User(
    uid=2,
    name=admin,
    ....,

    container=Container(
        id=1,

        items=[
            Item(...),
            Item(...),
            Item(...),
            Item(...)
        ],

        backpacks=[
            Backpack(
                container=1,

                backpackContainer=Container(
                    id=3,
                    items=null, /* Problem! Shouldn't be empty array [] at least or array with items? */
                    backpacks=null /* Problem! Shouldn't be empty array [] at least or array with backpacks? */
                )
            )
        ]
    )
)

As I annotated the result, nested fields items and backpacks are null, which suggests a huge problem. Hibernate tends to use empty sets instead of nulls, also I don't want to add null checkers everywhere.

What can cause this problem?

Also, this hierarchy is not infinite-deep, user's container may have as many backpacks as it wants, but those backpacks may not contain another backpacks.

4
  • Is the Container containing nulls a proxy (you can check that if it contains $ in the name of class instance)? Commented Jun 16, 2017 at 19:37
  • No, it isn't. I checked it. Commented Jun 16, 2017 at 19:46
  • I have updated my question because I forget to add something - mappedBy annotation. I also think, this might be a problem.. Commented Jun 16, 2017 at 19:59
  • That is a separate problem, of course you need to specify the inverse side, but it should not cause the issue described in this question. Please take a look at my answer below, it is the only explanation that comes to my mind. Commented Jun 16, 2017 at 20:35

1 Answer 1

2

The only logical explanation is that you are reading the User graph in the same persistence context (session) in which you have saved a new (transient) Container instance containing nulls which is assigned to the backpackContainer reference when loading and assembling the User graph afterwards.

Hibernate does not populate the associations when saving instances, but it does it when loading instances from the db, so you created it with nulls and it remained such in the persistence context. When you read the User graph afterwards, Hibernate reuses everything that is currently present in the persistence context including the Container instance which it assigns to the backpackContainer field.

So, you have two choices:

  • Update both sides of bidirectional relation if you actually intend to use both sides in the same persistence context (cleaner approach);
  • Or simply flush and clear the persistence context before reading the User (if you want everything to happen in the same transaction):

    entityManager.flush();
    entityManager.clear();
    
Sign up to request clarification or add additional context in comments.

2 Comments

Yes, you are right. I have queried User instance from database after persisting everything else and it's ok, so problem is solved. Anyway I need some more time find best solution to this problem.
The case is, first level elements are loaded eagerly, then I keep reference to User instance somewhere in my web browser session context.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.