Correct use of Session.persist ()

I'm trying to understand the semantics Session.persist()

and exactly what the object manager does with unsaved temporary instances. What I want to achieve is just add a new transient session to the session and start Hibernate INSERT

when the session is cleared.

I found that if a new instance persists and then changes over the course of one session, the Entity Manager will generate INSERT

and statements UPDATE

that can lead to constraint violations.

As an example, let's say I have an entity relationship Foo with a column column NOT NULL

and the following service.

@Transactional
void persistFoo(String bar) {
    Foo foo = new Foo();
    session.persist(foo);
    foo.setBar(bar);
}

      

Although we provide a value bar

, running this code will violate the NULL constraint on the database.

BatchUpdateException: Cannot insert the value NULL into column 'bar'

      

The Hibernate documentation states the following.

persist () makes the temporary instance persistent. However, this does not guarantee that the identifier value will be immediately assigned to the persistent instance, the assignment may occur during reset ...

INSERT

does indeed execute when the session is cleared at the end of the transactional block, but it is still parameterized with property values ​​from the object as it was when called persist()

.

I know that the specific problem that this example illustrates can be fixed with some simple changes, but I'm more interested in understanding how it should work.

My question is, is this behavior part of the contract Session.persist()

or can it be changed? If so, how do I tell the session to defer collecting parameters for the generated statement INSERT

until it is executed?

+3


source to share


1 answer


Yes, this is part of the contract Session.persist()

. According to the Hibernate documentation , this is the order in which SQL queries are executed:

  • Inserts, in the order of execution.
  • Updates
  • Removing collection items
  • Inserting collection items
  • Removes, in the order of execution.

This order is part of the official Hibernate API, and applications rely on it when manipulating their entity graphs.

Changes occurring after the Session.persist()

operators immediately INSERT

violate this contract and cause problems in some use cases.

Suppose we have an object User

and it is possible that the two users are somehow related to each other. Then we can insert them into one transaction:



persist(user1);
persist(user2);
user1.setPartner(user2);
user2.setPartner(user1);

      

If everything was stored in statements INSERT

, then we would get a foreign key constraint violation on save user1

.

In general, by ensuring that only the state that was passed to persist

ends in INSERT

, Hibernate gives us a lot of flexibility to meet the underlying DB constraints.

I am not aware of any configuration with which this behavior can be changed. Of course, as you mentioned, you can refactor your code to be persist

called after all values ​​are set, provided that DB constraints are not violated.

+1


source







All Articles