We are using Hibernate as persistency layer and have complex object model. Without exposing the real data model I want to explain the problem using the following simple example.
class Person {
private Integer id; //PK
private String name;
private Account account;
// other data, setters, getters
}
class Account {
private Integer id; //PK
// other data, setters, getters
}
The DB mapping is defined using HBM as following:
<class name="Person" table="PERSON">
<id name="id" column="ID">
<generator class="native"/>
</id>
<version name="version" type="java.lang.Long"/>
<property name="name" type="java.lang.String" length="50" column="NAME"/>
<many-to-one name="account" column="ACCOUNT_ID"
class="com.mycompany.model.Account"/>
</class>
I have to save new populated instance of Person
linked to existing Account
. The call is originated by web client, so at my layer I get instance of Person referenced to instance of Account
that holds its ID only.
If I try to call saveOrUpdate(person)
the following exception is thrown:
org.hibernate.TransientObjectException:
object references an unsaved transient instance - save the transient instance before flushing:
com.mycompany.model.Account
To avoid this I have to find the persisted object of Account
by ID and then call person.setAccount(persistedAccount)
. In this case everything works fine.
But in real life I deal with dozens of entities referenced to each other. I do not want to write special code for each reference.
I wonder whether there is some kind of generic solution for this problem.
@Entity annotation marks this class as an entity. @Table annotation specifies the table name where data of this entity is to be persisted. If you don't use @Table annotation, hibernate will use the class name as the table name by default. @Id annotation marks the identifier for this entity.
When you use . saveOrUpdate() Hibernate will check if the object is transient (it has no identifier property) and if so it will make it persistent by generating it the identifier and assigning it to session. If the object has an identifier already it will perform .
The most straightforward way to define an identifier is by using the @Id annotation. Simple ids are mapped using @Id to a single property of one of these types: Java primitive and primitive wrapper types, String, Date, BigDecimal and BigInteger.
To persist one entity, you just need to have the references to its direct dependencies. The fact that these other entities reference other entities doesn't matter.
The best way to do it is to get a proxy to the referenced entity, without even hitting the database, using session.load(Account.class, accountId)
.
What you're doing is the right thing to do: get a reference to the persistent account, and set this reference into the newly created account.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With