-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 1 post ] 
Author Message
 Post subject: orphanRemoval not functional
PostPosted: Wed Aug 18, 2010 3:45 pm 
Newbie

Joined: Wed Aug 18, 2010 3:17 pm
Posts: 1
Hello all, I currently have a problem with orphanRemoval = true when removing a child entity from the collection of a parent if the parent was just persisted in the current persistence context. I'm using hibernate 3.5.4 final as the JPA2 impl.

Here are my entities:

Code:
@Entity
public class Author
{
    @Id
    @GeneratedValue
    private Long id;

    private String firstName;

    private String lastName;

    @OneToMany(mappedBy = "author", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Book> books = new ArrayList<Book>();

    /* setters, getters, other code and fields*/
}

@Entity()
public class Book
{
    @Id
    @GeneratedValue
    private Long id;

    private String name;

    @Column(unique = true)
    private String isbn;

    @ManyToOne(optional = false)
    private Author author;

    /* setters, getters, other code and fields*/
}


Here is my unit test that produce the problem:

Code:

    Author john = new Author();
    john.setFirstName("John");
    john.setLastName("Doe");

    Book book1 = new Book();
    book1.setIsbn("1");
    book1.setName("Book 1");

    Book book2 = new Book();
    book2.setIsbn("2");
    book2.setName("Book 2");

    john.addBook(book1);
    john.addBook(book2);

    this.authorDAO.persist(john);

    Assert.assertEquals(2, john.getBooks().size());
    Assert.assertEquals(book1, john.getBooks().get(0));
    Assert.assertEquals(book2, john.getBooks().get(1));
    Assert.assertEquals(john, book1.getAuthor());
    Assert.assertEquals(john, book2.getAuthor());

    // this.authorDAO.refresh(john); // refreshing the entity before removing the books will work since the ArrayList of books become a PersistentBag

    book1.setAuthor(null);
    book2.setAuthor(null);
    john.getBooks().clear();

    this.authorDAO.flush();

    // exception thrown, see stack trace below


I get the following stack trace :

Code:
javax.persistence.PersistenceException: org.hibernate.PropertyValueException: not-null property references a null or transient value: com.acme.serviceplus.bookstore.entity.Book.author
   at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1235)
   at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1168)
   at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1174)
   at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:794)
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
   at java.lang.reflect.Method.invoke(Method.java:597)
   at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:240)
   at $Proxy29.flush(Unknown Source)
   at com.acme.serviceplus.service.BaseEntityDAOImpl.flush(BaseEntityDAOImpl.java:297)
   at com.acme.serviceplus.bookstore.TestDAO.testOneToMany_ManyToOne(TestDAO.java:600)
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
   at java.lang.reflect.Method.invoke(Method.java:597)
   at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
   at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
   at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
   at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
   at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
   at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
   at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
   at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:240)
   at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
   at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
   at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
   at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
   at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
   at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
   at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
   at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
   at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
   at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180)
   at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46)
   at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.hibernate.PropertyValueException: not-null property references a null or transient value: com.acme.serviceplus.bookstore.entity.Book.author
   at org.hibernate.engine.Nullability.checkNullability(Nullability.java:101)
   at org.hibernate.event.def.DefaultFlushEntityEventListener.scheduleUpdate(DefaultFlushEntityEventListener.java:309)
   at org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:155)
   at org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:219)
   at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:99)
   at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
   at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1206)
   at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:791)
   ... 36 more


I understand what is causing the problem. It's the fact that my initial implementation of list<Book> is an ArrayList. Clearing the list will not make hibernate aware of the change since it is not a PersistentCollection implementation. If I do a refresh before removing the books from the list, it works since the list implementation change to a PersistentBag after the refresh. Using a find, a save or a merge will not change anything since the current version in the context is the latest one.

From hibernate's documentation, we have the following information (page 103 of the hibernate core reference pdf):

Quote:

Notice how the instance variable was initialized with an instance of HashSet. This is the best way
to initialize collection valued properties of newly instantiated (non-persistent) instances. When you
make the instance persistent, by calling persist() for example, Hibernate will actually replace
the HashSet with an instance of Hibernate's own implementation of Set. Be aware of the following
errors:

Code:
Cat cat = new DomesticCat();
Cat kitten = new DomesticCat();
....
Set kittens = new HashSet();
kittens.add(kitten);
cat.setKittens(kittens);
session.persist(cat);
kittens = cat.getKittens(); // Okay, kittens collection is a Set
(HashSet) cat.getKittens(); // Error!




which is not true in my case. Is this a bug, an outdated documentation, something wrong on my part? Is there a way to change the ArrayList reference for a PersistentBag instance after the call to persist so that I don't need to refresh (and thus reload the entity from the DB I lost the other change i might have done).

Any help would be appreciated,

Regards


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 1 post ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.