Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

object references an unsaved transient instance: how to flush or return saved object

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?

like image 314
t777 Avatar asked Aug 17 '13 20:08

t777


People also ask

How do you fix the Hibernate object references an unsaved transient instance save the transient instance before flushing error?

By providing @OneToMany(cascade = {CascadeType. ALL}) , it tells Hibernate to save them to the database while saving the parent object. Save this answer.

What is transient instance in Java?

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.


2 Answers

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 @Identifier?

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

like image 109
Luca Basso Ricci Avatar answered Oct 30 '22 01:10

Luca Basso Ricci


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);
like image 34
Jason C Avatar answered Oct 30 '22 01:10

Jason C