[jboss-user] [EJB 3.0] - Only on specific scenario - "all-delete-orphan" was no longe

Oberiko do-not-reply at jboss.com
Thu Jan 24 16:15:54 EST 2008


Hello.

I have a demo app where the user can enter people and save them to a database.  Each person can have 0..* email addresses.  The user can also go to a seperate page where the people are listed and select one to edit (taking them back to the first screen, now pre-populated with the person data)

The following use cases work just fine:
* Save new person with and without emails
* Edit person with emails
* Edit person without emails, who formerly had emails
* Edit person (who had an email added, and removed before being saved)
* Save new person without email, go to list page, select the person, then edit them
* Etc.


What's odd is that in one scenario, it doesn't work.  That's if I create a new person, save them (without adding any emails), then modify them and save again (still without adding any emails).  If, at any point, I add an email, even without saving it, it works.

The error I get when this does happen is as such:
A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance

Here's the relevant snippets of my code:

  | @Stateful
  | @Name("editPerson")
  | public class EditPersonForm implements EditPersonLocal {
  | 	@PersistenceContext(type = EXTENDED)
  | 	private EntityManager em;
  | 
  | 	@In(required = false)
  | 	@Out(scope = ScopeType.PAGE)
  | 	private Person person;
  | 
  | 	@In(required = false)
  | 	@Out(required = false)
  | 	private EmailAddress emailAddress;
  | 
  | 	public void addEmail() {
  | 		log.info("Adding email address #0", emailAddress.getUrl());
  | 		person.addEmailAddress(emailAddress);
  | 
  | 		//Blank the email address entry point
  | 		emailAddress = new EmailAddress();
  | 	}
  | 
  | 	public void removeEmail(EmailAddress emailAddress) {
  | 		log.info("Removing email address #0", emailAddress.getUrl());
  | 		person.removeEmailAddress(emailAddress);
  | 	}
  | 
  | 	public void savePerson() {
  | 		if (person.getId() != null){
  | 			em.merge(person);
  | 		}
  | 		else {
  | 			em.persist(person);
  | 		}
  | 
  | 		// Note that the id of our person was generated and populated.
  | 		facesMessages.add("#0 was saved with an id of #1", person.getName(), person.getId());
  | 
  | 		log.info(person.getName() + " was saved.");
  | 	}
  | }
  | 


  | 			Name: 
  | 			<h:inputText value="#{person.name}" required="true"
  | 				requiredMessage="You need to enter a name" />
  | 			<h:outputText value="#{person.id}" />
  | 			<br />
  | 			<hr />			
  | 			Emails:<br />
  | 			URL: <h:inputText value="#{emailAddress.url}" />
  | 			<h:commandButton action="#{editPerson.addEmail()}" value="Add email" />
  | 
  | 			<h:dataTable id="emailTable" value="#{person.emailAddresses}"
  | 				var="email" rendered="#{not empty person.emailAddresses}">
  | 				<h:column>
  | 					<f:facet name="header">
  | 						<h:outputText value="URL" />
  | 					</f:facet>
  | 					<h:outputText value="#{email.url}" />
  | 				</h:column>
  | 				<h:column>
  | 					<f:facet name="header">
  | 						<h:outputText value="Action" />
  | 					</f:facet>
  | 					<h:commandButton value="Remove"
  | 						action="#{editPerson.removeEmail(email)}" />
  | 				</h:column>
  | 			</h:dataTable>
  | 			<hr />
  | 			<h:commandButton value="Save" action="#{editPerson.savePerson()}" />
  | 			<h:commandButton value="New" action="#{editPerson.newPerson()}" />
  | 


  | @Entity
  | @Name("person")
  | public class Person {
  | 
  | 	@Id @GeneratedValue
  | 	private Long id;
  | 	
  | 	@NotNull
  | 	private String name;
  | 	
  | 	@OneToMany(cascade = CascadeType.ALL, fetch=FetchType.EAGER, mappedBy="person")
  | 	@org.hibernate.annotations.Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
  | 	private Collection<EmailAddress> emailAddresses;
  | 	
  | 	public Long getId() {return id;}
  | 	public void setId(Long id) {this.id = id;}
  | 	
  | 	public String getName() {return name;}
  | 	public void setName(String name) {this.name = name;}
  | 	
  | 	public Collection<EmailAddress> getEmailAddresses() {
  | 		return emailAddresses;
  | 	}
  | 	public void setEmailAddresses(Collection<EmailAddress> emailAddresses) {
  | 		this.emailAddresses = emailAddresses;
  | 	}
  | 	public void addEmailAddress(EmailAddress email){
  | 		if (emailAddresses == null) emailAddresses= new ArrayList<EmailAddress>();
  | 		email.setPerson(this);
  | 		emailAddresses.add(email);
  | 	}
  | 	public void removeEmailAddress(EmailAddress emailAddress){
  | 		if (emailAddresses != null){
  | 			emailAddresses.remove(emailAddress);
  | 		}
  | 	}
  | }
  | 


  | @Entity
  | @Name("emailAddress")
  | public class EmailAddress {
  | 
  | 	@Id @GeneratedValue
  | 	private Long id;
  | 	
  | 	@NotNull
  | 	private String url;
  | 	
  | 	@ManyToOne
  | 	@JoinColumn(name="person_id")
  | 	private Person person;
  | 	
  | 	public Long getId() {return id;}
  | 	public void setId(Long id) {this.id = id;}
  | 	
  | 	public String getUrl() {
  | 		return url;
  | 	}
  | 	public void setUrl(String url) {
  | 		this.url = url;
  | 	}
  | 	
  | 	public Person getPerson() {
  | 		return person;
  | 	}
  | 	public void setPerson(Person person) {
  | 		this.person = person;
  | 	}
  | }
  | 

Now, I have found that if I put the following code right before the "em.merge(person)" (in the top code block), I no longer have this issue and it works.

  | if (person.getEmailAddresses() == null)
  |     person.setEmailAddresses(new ArrayList<EmailAddress>());
  | 

Is this a known issue?  Oh, and I apologize if this is isn't the correct forum for this, I wasn't sure if it was more EJB or Hibernate related.

View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4123200#4123200

Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4123200



More information about the jboss-user mailing list