Hibernate version:3.2.6
Code between sessionFactory.openSession() and session.close():I'm using Spring to do that
Name and version of the database you are using: MySQL, version: 5.0.51b-community-nt
Hi there,
I am having a problem with Hibernate inheritance. In the system that I plan to create, I have three types of objects; a location, and two types of coupons - active coupons and inactive coupons. Each location will have one active coupon associated with it, and one or many inactive coupons associated with it. Each time a new coupon is created for a location, if there is an existing coupon associated with it that is active, the old one becomes inactive and the new one automatically becomes the new one. I plan to have a class called 'Location', where it has a reference to a 'ActiveCoupon' object, and a collection of multiple 'PastCoupon' objects.
The ActiveCoupon and PostCoupon classes are subclasses from the Coupon class. Both of them have the exact same properties as the Coupon class. I intend to use inheritance in this system. What I wanted to do was to store the objects created from ActiveCoupon and PostCoupon in one table, which is why I used the table per class hierarchy strategy. Below is the hibernate mapping for my Location class mapping:
Code:
<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.rfid.data.entity">
<meta attribute="class-description">Represents a location</meta>
<class name="Location" table="Location">
<id name="id" type="long" column="locationID">
<generator class="native" />
</id>
<property name="locationName" type="string" />
<property name="distribution" type="boolean" />
<property name="locationFor" type="long" />
<one-to-one name="activeCoupon" class="ActiveCoupon" />
<bag name="pastCoupons" lazy="false" where="isActive = 'Inactive'">
<key column="locationID" />
<one-to-many class="PastCoupon" />
</bag>
</class>
<query name="fromLocation">
<![CDATA[
from Location
]]>
</query>
</hibernate-mapping>
My Coupon class mapping:
Code:
<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.rfid.data.entity">
<meta attribute="class-description">Represents a coupon</meta>
<class name="Coupon" table="Coupon" lazy="false">
<id name="id" type="long" column="couponID">
<generator class="native" />
</id>
<discriminator type="string" column="isActive" />
<property name="endDate" type="timestamp" />
<property name="startDate" type="timestamp" />
<property name="couponText" type="string" />
<many-to-one name="location" class="Location" column="locationID"
/>
<subclass name="ActiveCoupon" discriminator-value="Active">
</subclass>
<subclass name="PastCoupon" discriminator-value="Inactive">
<property name="expiryDate" type="timestamp" />
</subclass>
</class>
<query name="fromCoupon">
<![CDATA[
from Coupon
]]>
</query>
</hibernate-mapping>
And my Coupon code:
Code:
package com.rfid.data.entity;
import java.io.Serializable;
import java.util.Date;
@SuppressWarnings("serial")
public class Coupon implements Serializable
{
private long id;
private Date endDate;
private Date startDate;
private String couponText;
private Location location;
private String isActive;
public String getIsActive()
{
return isActive;
}
public void setIsActive(String isActive)
{
this.isActive = isActive;
}
public String getCouponText()
{
return couponText;
}
public void setCouponText(String couponText)
{
this.couponText = couponText;
}
public Location getLocation()
{
return location;
}
public void setLocation(Location location)
{
this.location = location;
}
public long getId()
{
return id;
}
public void setId(long id)
{
this.id = id;
}
public Date getStartDate()
{
return startDate;
}
public void setStartDate(Date startDate)
{
this.startDate = startDate;
}
public Date getEndDate()
{
return endDate;
}
public void setEndDate(Date endDate)
{
this.endDate = endDate;
}
}
And my location code:
Code:
package com.rfid.data.entity;
import java.util.Collection;
public class Location
{
private long id;
private String locationName;
private boolean distribution;
private long locationFor;
private ActiveCoupon activeCoupon;
private Collection<Coupon> pastCoupons;
public boolean isDistribution()
{
return distribution;
}
public void setDistribution(boolean distribution)
{
this.distribution = distribution;
}
public ActiveCoupon getActiveCoupon()
{
return activeCoupon;
}
public void setActiveCoupon(ActiveCoupon activeCoupon)
{
this.activeCoupon = activeCoupon;
}
public Collection<Coupon> getPastCoupons()
{
return pastCoupons;
}
public void setPastCoupons(Collection<Coupon> pastCoupons)
{
this.pastCoupons = pastCoupons;
}
public long getId()
{
return id;
}
public void setId(long id)
{
this.id = id;
}
public String getLocationName()
{
return locationName;
}
public void setLocationName(String locationName)
{
this.locationName = locationName;
}
public long getLocationFor()
{
return locationFor;
}
public void setLocationFor(long locationFor)
{
this.locationFor = locationFor;
}
}
One problem I initially encountered was changing the class type of the ActiveCoupon to a PostCoupon. I tried writing a property for the Coupon class named "isActive" (the same as the discriminator name) then changing it to "Inactive", but after persisting it the changes were not made to the DB. I then wrote a dirty way to change the type using a query:
Code:
public void changeActiveCouponType(Coupon activeCoupon)
{
session = getSession ( );
String hqlUpdate = "update Coupon set isActive = 'Inactive' where couponID = :id";
Query query = session.createQuery ( hqlUpdate );
query.setLong ( "id",activeCoupon.getId ( ) );
query.executeUpdate ( );
if ( session != null )
session.close ( );
}
It did make the changes, but unfortunately, after I inserted two coupons A and B (B should be active and A inactive) when I tried to get the location's Active Coupon after creating a new one it still retrieves A only. Meanwhile, the list of pastCoupons retrieves a list of ALL coupons, regardless of whether it is active or inactive. I inserted the where="isActive = 'Inactive'" property to it to trim down the results, but I expected Hibernate to do this for me. Can anyone tell me if there is a better way to change the subclass type and how to get Hibernate to correctly map the ActiveCoupon and PastCoupon properties correctly?
I would really appreciate it if someone could help me on this. Thanks in advance!