users@glassfish.java.net

Entity beans, persistence and CascadeType.

From: Ryan J <ryan.j_at_vacode.com>
Date: Wed, 27 Jun 2007 15:56:24 -0600

Hi,

I'm working with an application client and I'm running into an issue
when creating a new Entity and and persisting it via a remote interface.

The question I have is, when working with an application client and
detached Entity beans, how can I update the @Id field of child Entity
beans that are persisted via cascading?


Here's a stripped down example of how my entity beans would be set up
using a simple one to many (author to book) analogy:

> @Entity
> @Table(name = "AUTHOR")
> public class Author implements Serializable {
> public static final String PROPERTYNAME_ID = "id";
> public static final String PROPERTYNAME_BOOKS = "books";
>
> private int id;
> private Collection<Book> books;
>
> public Author() {
> this.id = -1;
> this.books = new ArrayList<Book>();
> }
>
> @Id
> @GeneratedValue(strategy = GenerationType.SEQUENCE)
> public int getId() {
> return id;
> }
>
> public void setId(int id) {
> this.id = id;
> }
>
> @OneToMany(fetch = FetchType.EAGER, mappedBy = Book.PROPERTYNAME_AUTHOR)
> public Collection<Book> getBooks() {
> return books;
> }
>
> public void setBooks(Collection<Book> books) {
> this.books = books;
> }
> }
>
> @Entity
> @Table(name = "BOOK")
> public class Book implements Serializable {
> public static final String PROPERTYNAME_ID = "id";
> public static final String PROPERTYNAME_AUTHOR = "author";
>
> private int id;
> private Author author;
>
> public Book() {
> this.id = -1;
> this.author = new Author();
> }
>
> @Id
> @GeneratedValue(strategy = GenerationType.SEQUENCE)
> public int getId() {
> return id;
> }
>
> public void setId(int id) {
> this.id = id;
> }
>
> @ManyToOne
> @JoinColumn(name = "AUTHOR_ID")
> public Author getAuthor() {
> return author;
> }
>
> public void setAuthor(Author author) {
> this.author = author;
> }
> }

When a new 'Author' is created with multiple 'Book'(s) I try to persist
using an approach that would be similar to the following
(EntitySaverRemote would be a remote interface that uses a
PersistenceContext):

Author a = new Author();
Book b1 = new Book();
Book b2 = new Book();

b1.setAuthor(a);
b2.setAuthor(a);

a.getBooks().add(b1);
a.getBooks().add(b2);

a.setId(EntitySaverRemote.saveAuthor(a));
b1.setId(EntitySaverRemote.saveBook(b1));
b2.setId(EntitySaverRemote.saveBook(b2));

Now, this is where I run into problems. I get the following exception:

> Caused by: java.rmi.RemoteException: null; nested exception is:
> java.lang.IllegalStateException: During synchronization a new object was found through a relationship that was not marked cascade PERSIST: [Author.toString() would be here] (0 items).

I can add CascadeType.PERSIST to the Author side of the relationship,
but then I'm not sure how I would set the id of the newly created Book
objects on the client side.

Any suggestions (or suggested reading)?

Ryan