5

I try to map a relation for the first time. I have found a lot of ways to go.

There are two classes: - Project (Parent) - Application (Child)

So one project can have several applications, but one application belongs to just one project..

I constructed them as follows:

Project.java

 import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.OneToMany; @Entity public class Project { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; @OneToMany(cascade = CascadeType.ALL) @JoinColumn(name = "project_id", nullable=false) @org.hibernate.annotations.IndexColumn(name = "project_index") List<Application> applications = new ArrayList<Application>(); [get and set methods...] } 

Application.java

import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; @Entity public class Application { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; @ManyToOne @JoinColumn(name = "project_id", updatable = false, insertable = false, nullable=false) private Project project; [get and set methods...] } 

...but, unfortunately I got an exception I can not deal with:

javax.servlet.ServletException: org.hibernate.PropertyValueException: not-null property references a null or transient value: ....common.entities.Application._applicationsBackref javax.faces.webapp.FacesServlet.service(FacesServlet.java:321) org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:359) org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:275) org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90) org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83) org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:343) org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:272) org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:83) root cause javax.faces.el.EvaluationException: org.hibernate.PropertyValueException: not-null property references a null or transient value: ....common.entities.Application._applicationsBackref javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:98) com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:98) javax.faces.component.UICommand.broadcast(UICommand.java:311) javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:781) javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1246) com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:77) com.sun.faces.lifecycle.Phase.doPhase(Phase.java:97) com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:114) javax.faces.webapp.FacesServlet.service(FacesServlet.java:308) org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:359) org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:275) org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90) org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83) org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:343) org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:272) org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:83) root cause org.hibernate.PropertyValueException: not-null property references a null or transient value: ....common.entities.Application._applicationsBackref org.hibernate.engine.Nullability.checkNullability(Nullability.java:95) org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:313) org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204) org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:130) org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210) org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:56) org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195) org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:50) org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93) 

Where is my mistake? I mean there is nothing null. Only on project side


When I remove @JoinColumn on owning side an exception occures:

java.sql.SQLException: Field 'project_id' doesn't have a default value 

Thank you Pascal

1
  • Can you show us what are you trying to put to database when this exception occures? How are you creating Application and Project? Commented Sep 7, 2010 at 9:05

3 Answers 3

19

There are several things to fix in your mapping.

  • Your association is bidirectional, you need to use the mappedBy attribute on the "One" side (or what you'll get is two unidirectional associations) to define the field that "owns" the relation on the owning side (the side that holds the foreign key i.e. the Many side in a one-to-many).
  • The @JoinColumn annotation should be defined on the owning side only, not both sides.
  • If you are using a JPA 2.0 compliant version of Hibernate (i.e. Hibernate 3.5+), prefer the standard @OrderColumn annotation of the Hibernate specific @IndexColumn
  • I'm not sure to understand why you defined the @JoinColumn as totally read-only with updatable = false, insertable = false, nullable=false, this doesn't sound appropriate.

So your mappings become (assuming you're using JPA 2.0):

@Entity public class Project { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; @OneToMany(cascade = CascadeType.ALL, mappedBy="project") @OrderColumn(name = "project_index") List<Application> applications = new ArrayList<Application>(); // getters, setters }

And

@Entity public class Application { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; @ManyToOne @JoinColumn(name = "project_id") private Project project; // getters, setters } 

And since your association, is bidirectional, don't forget to set both sides of the link when creating your object graph:

Project p = new Project(); Application a = new Application(); a.setProject(p); p.getApplications().add(a); em.persist(p); 

But I would actually recommend to create link management methods in your entities to set both sides of the link, e.g.

@Entity public class Project { ... public void addToApplications(Application app) { this.applications.add(app); app.setProject(this); } ... } 

Resources

References

  • JPA 1.0 specification
    • Section 2.1.8.2 "Bidirectional ManyToOne / OneToMany Relationships"
    • Section 9.1.24 "OneToMany Annotation"
    • Section 9.1.22 "ManyToOne Annotation"
  • JPA 2.0 specification
    • Section 11.1.39 "OrderColumn Annotation"
Sign up to request clarification or add additional context in comments.

3 Comments

One thing: List<Application> applications = new ArrayList<Application>();....that list should not be initialized or else the list gonna be empty after query... I had hibernate to initialize it!!!
@Sven Hmm... No, this is not true. There must be something else.
@Pascal why should this be bi-directional rather than uni-directional? How would the implementation change?
4

@JoinColumn annotation is not needed on both sides. In fact, you should only put this on owning side of the relationship.

Moreover, you have describe the thing as below,

@JoinColumn(name = "project_id", updatable = false, insertable = false, nullable=false)

Its totally making no sense. This, acutally, means that you don't want to update it, neither you like to insert it, nor you want it null.

Furthermore, you are missing @Column annotation upon your Id fields, in case the name of the actual column is not id.

3 Comments

when you say owning side, do you mean parent side? that's not clear to me
@Sven: Owning-side is the one which owns the foreign key. So, the entity for the table having foreign-key should be the owning-side. In your case it would be Application.
@Sven: Did I suggest you to remove it from the owning side? I think I said to keep it only there. :)
-1

Entity

@Table(name="Customer_v1") @Inheritance(strategy = InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.STRING) public class Customer implements Serializable{                                 @Id                 @Column(name="cust_id")                 protected int custId;  ------------------------------------------------ @Entity @DiscriminatorValue(value = "N") public class NewCustomer extends Customer {}   @Entity @DiscriminatorValue( value="E") public class ExistingCustomer extends Customer{} 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.