0
Library lib; //has a OneToMany rs to Book
lib = new Library();

Book book; //has a OneToMany rs to Letters
book = new Book(lib);
book.save()

book = new Book(lib);
book.merge() //.save() will throw an exception (detached entity passed to persist jpa) because of lib, so I merge it

Letters letters;
letters = new Letters(book);
letters.save(); //throws TransientPropertyValueException: object references an unsaved transient instance.

For testing purposes, I would like to create multiple books using the same library and save them. Also I would like to create multiple letters, using the same book and storing them aswell. But I don't know how to achieve this, because after merging(book), the book is not transient anymore..

thanks

edit: Added additional classes to make things more clear.

public abstract class Model implements Serializable {
/**
 * Save the current object in the database.
 *
 */
public void save() {
    EntityManager entityManager = HibernateUtil.getEntityManagerFactory().createEntityManager();
    entityManager.getTransaction().begin();
    entityManager.persist(this);
    entityManager.getTransaction().commit();
    entityManager.close();
}
/**
 * Delete the current object from the database.
 *
 */
public void delete() {
    EntityManager entityManager = HibernateUtil.getEntityManagerFactory().createEntityManager();
    entityManager.getTransaction().begin();
    entityManager.remove(entityManager.contains(this) ? this : entityManager.merge(this));
    entityManager.getTransaction().commit();
    entityManager.close();
}

public void merge(){
    EntityManager entityManager = HibernateUtil.getEntityManagerFactory().createEntityManager();
    entityManager.getTransaction().begin();
    entityManager.merge(this);
    entityManager.getTransaction().commit();
    entityManager.close();
}
}

Book Entity (Letter and Library Entity look the same)

@Entity
@Table(name = "book")
public class Book{

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "BOOK_ID")
private Integer id;

@OneToMany(fetch = FetchType.LAZY, mappedBy = "book", cascade = {CascadeType.ALL})
private List<Letters> letters;

 @ManyToOne(fetch = FetchType.LAZY,cascade = {CascadeType.ALL})
 @JoinColumn(name = "lib_id")
 Library library;

}

Lamevire
  • 15
  • 4
  • 2
    I can't really follow your explanations, but merge() doesn't attach the argument. It returns another, attached instance. – JB Nizet Nov 16 '16 at 22:32
  • @JB Nizet hm. where do you have problems with my explanation? And Iunderstand now the difference between save and merge but I still dont have a clue how to fix this in my code. – Lamevire Nov 16 '16 at 22:41
  • 1
    No. What I'm saying is that merge(foo) won't change anything to foo. It doesn't make foo a managed object. It **returns** another object that is managed. managedFoo = merge(foo). – JB Nizet Nov 16 '16 at 22:43
  • @JB Nizet yes I just realised this and edited my comment but I was too slow. So what are you suggesting? thanks – Lamevire Nov 16 '16 at 22:44
  • 1
    I'm not suggesting anything. I don't understand what your question or problem is, I don't know what you want to achieve, I know nothing about your entities, and this doesn't even look like JPA: entities don't have a save() and a merge() method. – JB Nizet Nov 16 '16 at 22:47
  • The problem is that I get an exception when trying to save letters. I now understand why I get the exception but I don't know how to fix it. And yes this is JPA (I edited the first post to make it more obvious). By looking at my code you know everything about my entitites. Book, has a library Object and it holds a ManyToOne relationship to Library and a OneToMany relationship to letters etc. – Lamevire Nov 16 '16 at 23:14
  • 1
    JPA's EntityManager does not have a save method, so this 'em' in your question isn't an EntityManager. A JPA EntityManager, as JB Nizet pointed out, takes in a detached entity instance and returns a different copy of it that is managed by the context. Use this instead: book= em.merge(book), or just use em.persist(book). – Chris Nov 17 '16 at 02:50

1 Answers1

0

What @JBNizet is intending to say is that you need to develop better your question, make it clearer!

Regarding your question, I suppose you have an entity structure similar to that:

Entity Library:

@Entity
@Table(name = "library")
public class Library {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "LIB_ID")
    private Integer id;

    @OneToMany(mappedBy = "library")
    private List<Book> books;

    // getters & setters
}

Entity Book:

@Entity
@Table(name = "book")
public class Book {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "BOOK_ID")
    private Integer id;

    @ManyToOne
    @JoinColumn(name = "LIB_ID")
    private Library library;

    @OneToMany(mappedBy = "book")
    private List<Letters> letters;

    // ...
}

Entity Letters:

@Entity
@Table(name = "letters")
public class Letters {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "LETTERS_ID")
    private Integer id;

    @ManyToOne
    @JoinColumn(name = "BOOK_ID")
    private Book book;

    // ...

}

This problem is usually related to the absence of cascade=CascadeType.ALL to your @ManyToOne mappings, as stated already here.

However, once you're opening a session, saving/merging every object and then commiting/closing it, you'd have to change the cascade type for your relationships. Do this:

  • Keep the cascade type of library object inside Book class as @ManyToOne(fetch = FetchType.LAZY, cascade = { CascadeType.ALL })
  • Change all the other cascades to CascadeType.MERGE. This way, every time JPA has to save the whole tree of objects, it'll always try to merge them.
Community
  • 1
  • 1
diogo
  • 3,769
  • 1
  • 24
  • 30
  • sorry, I thought it's obvious how the entitites look like with my description. But you are right..that's how the classes look like with one difference: I already included cascade = CascadeType.ALL else em.save(book); would alredy give me the detached entitiy exception. And you are wrong, I can't use save() twice on book which holds the same customer object because customer is not transient anymore after the first save. – Lamevire Nov 17 '16 at 09:44
  • *I meant "lib is not transient anymore" – Lamevire Nov 17 '16 at 09:58
  • Now I understood what you wanted. I updated my answer, take a look – diogo Nov 19 '16 at 03:06