-->
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.  [ 4 posts ] 
Author Message
 Post subject: Primary Key Associations and Subclassing oh my!
PostPosted: Wed Oct 19, 2005 9:55 am 
Newbie

Joined: Mon Apr 11, 2005 3:41 pm
Posts: 5
Need help with Hibernate? Read this first:
http://www.hibernate.org/ForumMailingli ... AskForHelp


Hello,

I have searched for an answer to this problem and worked on it for 2 days. I know I am doing something wrong, but can't figure it out so far.

I created a manager object, which is a subclass of an employee object. To implement this subclass relationship I used a discriminator column in the employee table. I also have an EmployeeName object which has a primary key association with Employee.

This is a legacy app, and I have no idea why the employee name is in a seperate table. Since it is a legacy app, the values of the primary keys in the employee and the employee name table must stay the same.

I need to make an Employee a Manager. I created a constructor in the Manager class that accepts an Employee. In the constructor I set all the attributes of the manager with the same values of the employee class including the id since it needs to stay the same.

I then delete the employee object.

The manager object now contains the employeeName object. To tell hibernate that the employeeName object needs to be persisted, I set its id attribute to -1. Thats where I get the error listed below.

I also have attributes of employee that are collections. When I apply them to the mgr object do I have to iterate the entire collection to tell hibernate to save each object?

Hope this makes sense
Hibernate version:

2.1

Mapping documents:


<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd" >

<hibernate-mapping>
<!--
Created by the Middlegen Hibernate plugin 2.1

http://boss.bekk.no/boss/middlegen/
http://www.hibernate.org/
-->
<class
name="com.knight.model.Employee"
table="EMPLOYEE"
discriminator-value="EMP"
>
<meta attribute="implement-equals" inherit="false">true</meta>
<meta attribute="session-method">HibernateUtil.getSession();</meta>

<id
name="id"
type="java.lang.Long"
column="EMPID"
>
<meta attribute="finder-method">findById</meta>
<meta attribute="use-in-tostring">true</meta>
<meta attribute="use-in-equals">true</meta>
<generator class="assigned"/>
</id>

<discriminator column="EMP_TYPE" type="string"/>

<property
name="gender"
type="java.lang.String"
column="GENDER"
length="1"
>
<meta attribute="finder-method">findByGender</meta>
<meta attribute="use-in-tostring">true</meta>
<meta attribute="use-in-equals">true</meta>
</property>
<property
name="birthDt"
type="java.sql.Date"
column="BIRTHDT"
length="7"
>
<meta attribute="finder-method">findByBirthDate</meta>
<meta attribute="use-in-tostring">true</meta>
<meta attribute="use-in-equals">true</meta>
</property>
<property
name="ssn"
type="java.lang.String"
column="SSN"
length="9"
>
<meta attribute="finder-method">findBySsn</meta>
<meta attribute="use-in-tostring">true</meta>
<meta attribute="use-in-equals">true</meta>
</property>
<property
name="adpFileNum"
type="java.lang.String"
column="ADPFILENUM"
length="8"
>
<meta attribute="finder-method">findByAdpFileNum</meta>
<meta attribute="use-in-tostring">true</meta>
</property>
<property
name="comments"
type="java.lang.String"
column="COMMENTS"
length="40"
/>
<property
name="userId"
type="java.lang.Long"
column="USERID"
length="4"
>
<meta attribute="use-in-tostring">true</meta>
</property>
<property
name="moddt"
type="java.sql.Date"
column="MODDT"
length="7"
>
<meta attribute="use-in-tostring">true</meta>
</property>
<property
name="mclaglanCode"
type="java.lang.String"
column="MCLAG"
length="9"
>
<meta attribute="finder-method">findByMclaglanCode</meta>
</property>

<property
name="producer"
type="java.lang.String"
column="PRODUCER"
length="1"
>
<meta attribute="finder-method">findByProducer</meta>
<meta attribute="use-in-tostring">true</meta>
</property>
<property
name="hireDate"
type="java.sql.Date"
column="HIREDT"
length="7"
>
<meta attribute="finder-method">findByHireDate</meta>
<meta attribute="use-in-tostring">true</meta>
</property>
<property
name="company"
type="java.lang.String"
column="COMPANY"
length="5"
>
<meta attribute="use-in-tostring">true</meta>
</property>
<property
name="costcenter"
type="java.lang.String"
column="COSTCENTER"
length="60"
>
<meta attribute="use-in-tostring">true</meta>
</property>
<property
name="corporateTitleDescr"
type="java.lang.String"
column="CORPTITLE"
length="50"
>
<meta attribute="use-in-tostring">true</meta>
</property>
<property
name="functionalTitle"
type="java.lang.String"
column="FUNCTITLE"
length="60"
>
<meta attribute="finder-method">findByFunctionalTitle</meta>
<meta attribute="use-in-tostring">true</meta>
</property>
<property
name="location"
type="java.lang.String"
column="LOCATION"
length="30"
>
<meta attribute="use-in-tostring">true</meta>
</property>
<property
name="status"
type="java.lang.String"
column="STATUS"
length="20"
>
<meta attribute="use-in-tostring">true</meta>
</property>
<property
name="termDate"
type="java.sql.Date"
column="TERMDT"
length="7"
>
<meta attribute="finder-method">findByTermDate</meta>
<meta attribute="use-in-tostring">true</meta>
</property>
<property
name="costCenterId"
type="java.lang.String"
column="COSTCTR"
length="6"
>
<meta attribute="finder-method">findByCostCenterId</meta>
</property>
<property
name="locationId"
type="java.lang.String"
column="LOCODE"
length="3"
>
<meta attribute="finder-method">findByLocationId</meta>
</property>
<property
name="companyCode"
type="java.lang.String"
column="COMPCODE"
length="4"
>
<meta attribute="finder-method">findByCompanyCode</meta>
</property>
<property
name="employmentStatus"
type="java.lang.String"
column="STAT"
length="1"
>
<meta attribute="finder-method">findByEmploymentStatus</meta>
<meta attribute="use-in-tostring">true</meta>
</property>
<property
name="intlStatus"
type="java.lang.String"
column="INTLSTATUS"
length="25"
>
<meta attribute="finder-method">findByInternationalStatus</meta>
<meta attribute="use-in-tostring">true</meta>
</property>
<property
name="category"
type="java.lang.String"
column="CATEGORY"
length="25"
>
<meta attribute="finder-method">findByCategory</meta>
<meta attribute="use-in-tostring">true</meta>
</property>
<property
name="corpTitleCode"
type="java.lang.String"
column="CTITLECODE"
length="15"
>
<meta attribute="finder-method">findByCorporateTitle</meta>
</property>
<property
name="registered"
type="java.lang.String"
column="REGISTERED"
length="1"
>
<meta attribute="finder-method">findByRegistered</meta>
<meta attribute="use-in-tostring">true</meta>
</property>
<property
name="hAndDTraining"
type="java.lang.String"
column="HANDTRNG"
length="1"
>
<meta attribute="finder-method">findByHAndDTraining</meta>
<meta attribute="use-in-tostring">true</meta>
</property>
<property
name="benefitTier"
type="java.lang.Integer"
column="BENEFITTIER"
length="2"
>
<meta attribute="finder-method">findByBenefitTier</meta>
<meta attribute="use-in-tostring">true</meta>
</property>
<!-- Associations -->

<!-- bi-directional one-to-many association to EmployeeCompensation -->
<set
name="employeeCompensations"
lazy="true"
inverse="true"
cascade="all"
>
<key>
<column name="EMPID"/>
</key>
<one-to-many
class="com.knight.model.EmployeeCompensation"
/>
</set>
<!-- uni-directional one-to-many association to EmployeeActivity -->
<set
name="employeeActivities"
lazy="true"
inverse="true"
cascade="all"
>
<key>
<column name="EMPID"/>
</key>
<one-to-many
class="com.knight.model.EmployeeActivity"
/>
</set>
<!-- bi-directional one-to-one association to EmployeeName -->
<one-to-one
name="employeeName"
class="com.knight.model.EmployeeName"
cascade="all"
outer-join="auto"
/>
<!-- bi-directional many-to-one association to Manager -->
<many-to-one
name="manager"
class="com.knight.model.Manager"
not-null="true"
>
<meta attribute="use-in-equals">true</meta>
<column name="MGR_ID"/>
</many-to-one>
<!-- uni-directional many-to-one association to Lookup -->
<many-to-one
name="lookupByEeoCode"
class="com.knight.model.Lookup"
>
<meta attribute="finder-method">findByEeoCode</meta>
<column name="EEOCODE"/>
</many-to-one>
<!-- uni-directional many-to-one association to Lookup -->
<many-to-one
name="lookupByMaritalStatus"
class="com.knight.model.Lookup"
>
<meta attribute="finder-method">findByMaritalStatus</meta>
<column name="MARITALSTAT"/>
</many-to-one>
</class>
</hibernate-mapping>


<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd" >

<hibernate-mapping>
<!--
Created by the Middlegen Hibernate plugin 2.1

http://boss.bekk.no/boss/middlegen/
http://www.hibernate.org/
-->
<class
name="com.knight.model.EmployeeName"
table="EMPLOYEE_NAME"
>
<meta attribute="implement-equals" inherit="false">true</meta>
<meta attribute="session-method">HibernateUtil.getSession();</meta>
<id
name="id"
type="java.lang.Long"
column="EMPID"
unsaved-value="-1"
>
<meta attribute="finder-method">findById</meta>
<meta attribute="use-in-equals">true</meta>
<generator class="foreign">
<param name="property">employee</param>
</generator>
</id>
<property
name="lname"
type="java.lang.String"
column="LNAME"
length="40"
>
<meta attribute="finder-method">findByLastName</meta>
<meta attribute="use-in-tostring">true</meta>
<meta attribute="use-in-equals">true</meta>
</property>
<property
name="fname"
type="java.lang.String"
column="FNAME"
length="40"
>
<meta attribute="finder-method">findByFirstName</meta>
<meta attribute="use-in-tostring">true</meta>
<meta attribute="use-in-equals">true</meta>
</property>
<property
name="mname"
type="java.lang.String"
column="MNAME"
length="25"
>
<meta attribute="use-in-tostring">true</meta>
<meta attribute="use-in-equals">true</meta>
</property>
<property
name="maidename"
type="java.lang.String"
column="MAIDENAME"
length="70"
>
<meta attribute="use-in-tostring">true</meta>
</property>
<property
name="goesby"
type="java.lang.String"
column="GOESBY"
length="70"
>
<meta attribute="use-in-tostring">true</meta>
</property>
<property
name="userid"
type="java.lang.Long"
column="USERID"
length="4"
/>
<property
name="moddt"
type="java.sql.Date"
column="MODDT"
length="7"
/>

<!-- Associations -->
<!-- bi-directional one-to-one association to Employee -->
<one-to-one
name="employee"
class="com.knight.model.Employee"
outer-join="auto"
constrained="true"
/>
</class>
</hibernate-mapping>

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd" >

<hibernate-mapping>
<!--
Created by the Middlegen Hibernate plugin 2.1

http://boss.bekk.no/boss/middlegen/
http://www.hibernate.org/
-->
<subclass
name="com.knight.model.Manager"
discriminator-value="MGR"
extends="com.knight.model.Employee"
>
<meta attribute="implement-equals" inherit="false">true</meta>
<meta attribute="session-method"> HibernateUtil.getSession();</meta>
<!-- Associations -->

<!-- bi-directional one-to-many association to Employee -->
<set
name="employees"
lazy="true"
inverse="true"
cascade="none"
>
<key>
<column name="MGR_ID"/>
</key>
<one-to-many
class="com.knight.model.Employee"
/>
</set>
</subclass>
</hibernate-mapping>


Code between sessionFactory.openSession() and session.close():

HibernateUtil.beginTransaction();
List employees = EmployeeFinder.findById(new Long(employeesSubmitted[i]));
Employee employee = (Employee) employees.get(0);
Manager manager = new Manager(employee);
manager.getEmployeeName().setId(new Long(-1));
HibernateUtil.getSession().delete(employee);
HibernateUtil.getSession().save(manager);
HibernateUtil.commitTransaction();

Full stack trace of any exception that occurs:

net.sf.hibernate.HibernateException: identifier of an instance of com.knight.model.EmployeeName altered from 3030 to -1
at net.sf.hibernate.impl.SessionImpl.checkId(SessionImpl.java:2670)
at net.sf.hibernate.impl.SessionImpl.flushEntity(SessionImpl.java:2493)
at net.sf.hibernate.impl.SessionImpl.flushEntities(SessionImpl.java:2486)
at net.sf.hibernate.impl.SessionImpl.flushEverything(SessionImpl.java:2281)
at net.sf.hibernate.impl.SessionImpl.flush(SessionImpl.java:2260)
at net.sf.hibernate.impl.SessionImpl.forceFlush(SessionImpl.java:769)
at net.sf.hibernate.impl.SessionImpl.doSave(SessionImpl.java:849)
at net.sf.hibernate.impl.SessionImpl.saveWithGeneratedIdentifier(SessionImpl.java:790)
at net.sf.hibernate.impl.SessionImpl.save(SessionImpl.java:749)
at com.knight.empHierarchy.AddReplaceMgrServlet.doPost(AddReplaceMgrServlet.java:68)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:760)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
at weblogic.servlet.internal.ServletStubImpl$ServletInvocationAction.run(ServletStubImpl.java:1006)
at weblogic.servlet.internal.ServletStubImpl.invokeServlet(ServletStubImpl.java:419)
at weblogic.servlet.internal.ServletStubImpl.invokeServlet(ServletStubImpl.java:315)
at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:6718)
at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:121)
at weblogic.servlet.internal.WebAppServletContext.invokeServlet(WebAppServletContext.java:3764)
at weblogic.servlet.internal.ServletRequestImpl.execute(ServletRequestImpl.java:2644)
at weblogic.kernel.ExecuteThread.execute(ExecuteThread.java:219)
at weblogic.kernel.ExecuteThread.run(ExecuteThread.java:178)

Name and version of the database you are using:

Oracle 9i
The generated SQL (show_sql=true):



Debug level Hibernate log excerpt:


Top
 Profile  
 
 Post subject: Won't work
PostPosted: Wed Oct 19, 2005 3:29 pm 
Newbie

Joined: Wed Sep 17, 2003 3:31 am
Posts: 10
Location: Napoli (IT)
Usually you cannot change the type of an object during the life cycle of a Session. First, I suggest not to map Manager as a subclass of Employee.
Instead, you could create only one class and map the discriminator column 'MGR' as an enumeration.

If you really like this class hierarchy you have to make the session forget the old object. Try a dirty solution creating the new object after cleared the session:

Code:

HibernateUtil.beginTransaction();
List employees = EmployeeFinder.findById(new Long(employeesSubmitted[i]));
Employee employee = (Employee) employees.get(0);
Manager manager = new Manager(employee);

Session session = HibernateUtil.getSession();

session.delete(employee);
session.flush();

HibernateUtil.getSession().clear(); // also try session.evict(employee)

session.save(manager);

HibernateUtil.commitTransaction();




Not guaranteed.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Oct 19, 2005 3:42 pm 
Newbie

Joined: Mon Apr 11, 2005 3:41 pm
Posts: 5
Thanks for your reply.

I am going to try your code solution. Since only mgrs have a collection of employees, I dont want to create a single class, because then employees would have a collection of employees.

For now, I am updating the discriminator column with a jdbc update. Seems to be working. Bit of a hack though


Top
 Profile  
 
 Post subject: FK issues
PostPosted: Wed Oct 19, 2005 6:12 pm 
Newbie

Joined: Wed Sep 17, 2003 3:31 am
Posts: 10
Location: Napoli (IT)
Now that I see the code again: session.delete(employee) might cause FK violation if the record is referenced somewhere, as it surely is.

In such a case try with this:

Code:

Employee employee = (Employee) employees.get(0);
Manager manager = new Manager(employee);
Session session = HibernateUtil.getSession();

session.evict(employee);
session.update(manager);




It's ever simpler.

_________________
--- stefano
Don't forget to rate.


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

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.