Summary:
This post looks huge because I tried to answer all the questions, but its pretty simple.
Consider 2 tables:
User
UserType
As you'd expect, User has a FK "user_type_id" that points to the UserType.id table. The tables would conceptually look something like this:
User Table (user_name, user_type_id)
"bob", 2
"sally", 2
"john", 1
UserType Table (id, name)
1, "Administrator"
2, "Normal User"
And that's basically the idea... below you can see that I added a property to my User entity for get/setting the "UserType" object, and its a many-to-one based on the "user_type_id" field.
Now the problem is when I load up a UserType (in my case I have some code to load up a default new user type) and assign it to the User, then try and save the user... the exception below is thrown. I found another thread where some gentleman were trying a similar relationship representing a Person and his/her Address object... Christian said that what they are trying to do is likely impossible and mentioned moving some FK into the Address table.
Now as many Hibernate beginners, conceptually this seems so straight forward to me that there is no other way to do it... am I missing something? I also have Hib in Action if you want to refer me to a chapter.
Thanks so much for any help... I wish I had a more interesting question to ask ;)
Best,
Riyad
Hibernate version:
2.17c
Mapping document - User.hbm.xml:
Code:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 1.1//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-1.1.dtd">
<hibernate-mapping
>
<class
name="com.kallasoft.web.dto.User"
table="user"
>
<id
name="id"
column="id"
type="java.lang.Integer"
>
<generator class="native">
<!--
To add non XDoclet generator parameters, create a file named
hibernate-generator-params-User.xml
containing the additional parameters and place it in your merge dir.
-->
</generator>
</id>
<many-to-one
name="userType"
class="com.kallasoft.web.dto.UserType"
cascade="none"
outer-join="auto"
column="user_type_id"
not-null="true"
/>
<property
name="userName"
type="java.lang.String"
column="user_name"
/>
<property
name="password"
type="java.lang.String"
column="password"
/>
<property
name="disabled"
type="java.lang.Boolean"
column="disabled"
/>
<property
name="disabledMessage"
type="java.lang.String"
column="disabled_message"
/>
<property
name="timestampCreated"
type="java.lang.Long"
column="timestamp_created"
/>
<property
name="timestampLastLogin"
type="java.lang.Long"
column="timestamp_last_login"
/>
<one-to-one
name="userProfile"
class="com.kallasoft.web.dto.UserProfile"
cascade="none"
outer-join="auto"
constrained="false"
/>
<!--
To add non XDoclet property mappings, create a file named
hibernate-properties-User.xml
containing the additional properties and place it in your merge dir.
-->
</class>
</hibernate-mapping>
Mapping document - UserType.hbm.xml:Code:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 1.1//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-1.1.dtd">
<hibernate-mapping
>
<class
name="com.kallasoft.web.dto.UserType"
table="user_type"
>
<id
name="id"
column="id"
type="java.lang.Integer"
>
<generator class="native">
<!--
To add non XDoclet generator parameters, create a file named
hibernate-generator-params-UserType.xml
containing the additional parameters and place it in your merge dir.
-->
</generator>
</id>
<property
name="name"
type="java.lang.String"
column="name"
/>
<property
name="description"
type="java.lang.String"
column="description"
/>
<property
name="systemAdministrator"
type="java.lang.Boolean"
column="system_administrator"
/>
<property
name="administrator"
type="java.lang.Boolean"
column="administrator"
/>
<property
name="editor"
type="java.lang.Boolean"
column="editor"
/>
<property
name="normal"
type="java.lang.Boolean"
column="normal"
/>
<property
name="newUserDefault"
type="java.lang.Boolean"
column="new_user_default"
/>
<!--
To add non XDoclet property mappings, create a file named
hibernate-properties-UserType.xml
containing the additional properties and place it in your merge dir.
-->
</class>
</hibernate-mapping>
Code between sessionFactory.openSession() and session.close():Code:
UserType defaultUserType = UserTypeDAO.getInstance().readNewUserDefault();
Long timestamp = new Long(System.currentTimeMillis());
User user = new User(defaultUserType, getUserName(), getPassword(), Boolean.FALSE, null, timestamp, timestamp);
Integer id = UserDAO.getInstance().createUser(user); // <-- THIS IS WHERE EXCEPTION IS THROWN
Full stack trace of any exception that occurs:
Quote:
net.sf.hibernate.PropertyValueException: not-null property references a null or transient value: com.kallasoft.web.dto.User.userType
at net.sf.hibernate.impl.SessionImpl.checkNullability(SessionImpl.java:1286)
at net.sf.hibernate.impl.SessionImpl.doSave(SessionImpl.java:937)
at net.sf.hibernate.impl.SessionImpl.doSave(SessionImpl.java:866)
at net.sf.hibernate.impl.SessionImpl.saveWithGeneratedIdentifier(SessionImpl.java:784)
at net.sf.hibernate.impl.SessionImpl.save(SessionImpl.java:747)
at com.kallasoft.web.dao.AbstractDAO.createObject(AbstractDAO.java:76)
at com.kallasoft.web.dao.UserDAO.createUser(UserDAO.java:32)
at com.kallasoft.web.bean.UserBean.registerUser(UserBean.java:98)
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:324)
at com.sun.faces.el.MethodBindingImpl.invoke(MethodBindingImpl.java:126)
at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:72)
at javax.faces.component.UICommand.broadcast(UICommand.java:312)
at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:267)
at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:381)
at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:75)
at com.sun.faces.lifecycle.LifecycleImpl.phase(LifecycleImpl.java:200)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:90)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:197)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:237)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:157)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:214)
at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
at org.apache.catalina.core.StandardContextValve.invokeInternal(StandardContextValve.java:198)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:152)
at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:462)
at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:102)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:137)
at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:118)
at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:102)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:929)
at org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:160)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:799)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnection(Http11Protocol.java:705)
at org.apache.tomcat.util.net.TcpWorkerThread.runIt(PoolTcpEndpoint.java:577)
at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:683)
at java.lang.Thread.run(Thread.java:534)
Name and version of the database you are using:
MySQL 4.1.7
The generated SQL (show_sql=true):
n/a, none is printed out