I use Spring 3.2.3 and Hibernate 4.2.3 and JDK 7.
I have a simple entity:
@Entity
public class Language {
@Id
@GeneratedValue
private long id;
@Column(nullable = false, length = 3, unique = true)
private String code;
}
I saved an instance of this entity using a @Service
annotated class with a @Transactional
annotated method which uses a DAO which saves the entity with
sessionFactory.getCurrentSession().save(object);
After that I used the saved Language
entity for creating EntityX
, which used it in an ManyToOne
relation ...
lang=new Language();
// ...
languageService.saveLanguage(lang);
e=new EntityX();
// ...
e.setLanguage(lang);
otherService.saveEntity(e);
and EntityX
is defined as ...
@Entity
public class EntityX {
@ManyToOne
@JoinColumn(nullable = false)
private Language language;
// ...
}
I always get the exception
Exception in thread "main" org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: somepackage.Language
I try to use some cascade-definitions in EntityX
's relation to Language
as suggested in other posts, but it has no effect.
If I reload the saved Language
entity by finding it by its code
using some HQL-query, then everything works fine, but that it is far away from being 'nice'.
Unfortunately the save(...)
method(s) of org.hibernate.Session
does not return the saved object.
Has anybody any ideas how to solve it?
By providing @OneToMany(cascade = {CascadeType. ALL}) , it tells Hibernate to save them to the database while saving the parent object. Save this answer.
1. Transient State: A New instance of a persistent class which is not associated with a Session, has no representation in the database and no identifier value is considered transient by Hibernate: UserDetail user = new UserDetail(); user.setUserName("Dinesh Rajput"); // user is in a transient state. Popular Tutorials.
Is you code in a single @Transactional
method?
If not the problem can be that, after any call to service method, transaction will be commit and session cleared. When you try to save entity, language object is not detected in session and managed as transient instance and give the error.
In case your code is under single transaction did you try a flush()
before saving entity to force Hibernate store Language
to database and assign it a valid @Id
entifier?
After all - IMHO - if you have a dependency from Entity and Language the best choice is:
@ManyToOne(cascade = CascadeType.ALL)
private Language language;
and change your code as:
e=new EntityX();
Language lang = new Language();
// ...
e.setLanguage(lang);
otherService.saveEntity(e);
and you don't need to persist entity in two steps (language + entity); manage language+entity as single item
PS: The save(...) method(s) of org.hibernate.Session does not return the saved object because the object will remain the same (reference doesn't change), just object properties changes (like the one marked this @Id
, for example)!
EDIT:
Make an object persistent (session.save() it I mean) don't result in a immediate insert/update; without cascade hint Hibernate look doesn't detect dependency between EntityX and Language and doesn't perform a sql insert of Language before saving EntityX.
languageService.save(language) call doesn't perform session.flush() because you are under same @Transactional
and without session.commit() no session.flush() is performed and best option is that Language object is still marked as transient.
You can do a check: extract services save code (language entityX) and put all in single @Transactional
and check if Hibernate still give you error.
My best option is still perform a flush() in the middle or change your mapping, no other way
First, if the code
field is the primary key (or you are at least using it as your primary ID for Hibernate), specify @Id:
@Id
@GeneratedValue(generator="assigned")
@Column(length = 3)
private String code;
Not specifying an ID column could be confusing Hibernate a bit; although don't quote me on that.
If save()
still doesn't work after that, you can use merge()
:
Language lang = new Language("XYZ");
lang = session.merge(lange);
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