-->
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.  [ 5 posts ] 
Author Message
 Post subject: Query retrieving duplicate records
PostPosted: Thu Jan 31, 2008 5:02 am 
Regular
Regular

Joined: Tue Apr 10, 2007 10:02 am
Posts: 56
I'm using Hibernate as the DAO within a Spring business tier.

For one 'findQuery' call the resultant list contains 3 times the number of records that actually exist, i.e. there are 7 records, and the query is returning 21 ( i.e. 3 instances of each real record).

Code:
   private final static String ANALYSIS = "Analysis";
   private final static String ANALYSIS_PATH = "com.eis.risk.analysis." + ANALYSIS;

         String aQuery = "from " + ANALYSIS_PATH + " as model order by model." + ANALYSIS_TITLE;
         List aList = getHibernateTemplate().find(aQuery); // returns 21 records - when it should be 7


The situation is complicated by the fact that I have three Hibernate mappings onto this single table, and I'm wondering if this the cause.

The first mapping 'Rma.hbm.xml' - maps to the main table itself. This is the mapping used on my call that is returning the 21 records. The second mapping 'RmaInfo.hbm.xml' links in two associated tables to bring back status info as a composite object. The third mapping 'RmaPlus.hbm.xml' links in a host of tables to bring back lots of subordinate data.

The second mapping type 'RmaInfo.hbm.xml' would have been called prior to my call that uses 'Rma.hbm.xml'. Is the latter picking up cached data from the earlier call?

Any ideas?

Here are the class definitions and hbm files....


----oOo---

First the start of the class definition...

Code:
public class Analysis extends AliasNamedEntity implements Serializable {
   private static final long serialVersionUID = -644896087713571799L; 
   private String fProjectID = null;
   private int fCurrencyID = ID_UNASSIGNED;
   private int fCurrencyRateTypeID = ID_UNASSIGNED;
   private int fVersion = ID_UNASSIGNED;
   private boolean fUseAliasFormat = false;
   private int fAliasFormatID = ID_UNASSIGNED;


... and the related Hibernate mapping...

Rma.hbm.xml
Code:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
    Mapping file autogenerated by MyEclipse - Hibernate Tools
-->
<hibernate-mapping>
    <class name="com.eis.risk.analysis.Analysis" table="rma">
        <id name="ID" type="java.lang.Integer" unsaved-value="-1">
            <column name="RmaID" />
            <generator class="native" />
        </id>
        <version name="version" column="RmaVersion"/>
       
        <property name="title" type="java.lang.String">
            <column name="RmaTitle" length="50" />
        </property>
        <property name="alias" type="java.lang.String">
            <column name="RmaAlias" length="20" not-null="true" unique="true" />
        </property>
        <property name="desc" type="java.lang.String">
            <column name="RmaDesc" length="65535" />
        </property>
        <property name="projectID" type="java.lang.String">
            <column name="ProjectID" />
        </property>
        <property name="currencyID" type="java.lang.Integer">
            <column name="CurrencyID" not-null="true" />
        </property>
        <property name="currencyRateTypeID" type="java.lang.Integer">
            <column name="CurrencyRateTypeID" not-null="true" />
        </property>
        <property name="useAliasFormat" type="java.lang.Boolean">
            <column name="RmaUseAliasFormat" />
        </property>
        <property name="aliasFormatID" type="java.lang.Integer">
            <column name="AliasFormatID" />
        </property>
    </class>
</hibernate-mapping>


----oOo---

The start of the class definition...
Code:
public class AnalysisInfo extends Analysis {
   private static final long serialVersionUID = -6216981111520585437L;
   private AnalysisStatusPoint fLatestStatus;
   private AnalysisLock fLock;


... and the related Hibernate mapping...


RmaInfo.hbm.xml
Code:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
    Mapping file autogenerated by MyEclipse - Hibernate Tools
-->
<hibernate-mapping>
    <class name="com.eis.risk.analysis.AnalysisInfo" table="rma">
        <id name="ID" type="java.lang.Integer" unsaved-value="-1">
            <column name="RmaID" />
            <generator class="native" />
        </id>
        <version name="version" column="RmaVersion"/>
        <property name="title" type="java.lang.String">
            <column name="RmaTitle" length="50" />
        </property>
        <property name="alias" type="java.lang.String">
            <column name="RmaAlias" length="20" not-null="true" unique="true" />
        </property>
        <property name="desc" type="java.lang.String">
            <column name="RmaDesc" length="65535" />
        </property>
        <property name="projectID" type="java.lang.String">
            <column name="ProjectID" />
        </property>
        <property name="currencyID" type="java.lang.Integer">
            <column name="CurrencyID" not-null="true" />
        </property>
        <property name="currencyRateTypeID" type="java.lang.Integer">
            <column name="CurrencyRateTypeID" not-null="true" />
        </property>
        <property name="useAliasFormat" type="java.lang.Boolean">
            <column name="RmaUseAliasFormat" />
        </property>
        <property name="aliasFormatID" type="java.lang.Integer">
            <column name="AliasFormatID" />
        </property>
        <join table="rma_latest_status_point">
           <key column="RmaID" unique="true"/>
           <many-to-one name="latestStatus"
                        column="PointID" not-null="true" unique="true" lazy="false"/>
        </join>
        <join table="rma_lock" optional="true">
           <key column="RmaID" unique="true" />
           <many-to-one name="lock" class="com.eis.risk.analysis.AnalysisLock"
                        column="RmaLockID" unique="true" lazy="false"/>
        </join>
    </class>
</hibernate-mapping>


----oOo---

The start of the class definition...
Code:
public class AnalysisPlus extends Analysis {
   private static final long serialVersionUID = -4637247788793525640L; 
   private Set<FolderEntry> fFolderEntries = new HashSet<FolderEntry>();
   private Set<LatestPointLink> fLatestPointLink = new HashSet<LatestPointLink>();
   private Set<AnalysisLock> fLocks = new HashSet<AnalysisLock>();
   private Set<AnalysisStatusPoint> fStatusPoints = new HashSet<AnalysisStatusPoint>();
   private Set<RiskEntryPlus> fRiskEntries = new HashSet<RiskEntryPlus>();


... and the related Hibernate mapping...
Code:
[B]RmaPlus.hbm.xml[/B]
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
    Mapping file autogenerated by MyEclipse - Hibernate Tools
-->
<hibernate-mapping>
    <class name="com.eis.risk.analysis.AnalysisPlus" table="rma">
        <id name="ID" type="java.lang.Integer" unsaved-value="-1">
            <column name="RmaID" />
            <generator class="native" />
        </id>
        <version name="version" column="RmaVersion"/>
        <property name="title" type="java.lang.String">
            <column name="RmaTitle" length="50" />
        </property>
        <property name="alias" type="java.lang.String">
            <column name="RmaAlias" length="20" not-null="true" unique="true" />
        </property>
        <property name="desc" type="java.lang.String">
            <column name="RmaDesc" length="65535" />
        </property>
        <property name="projectID" type="java.lang.String">
            <column name="ProjectID" />
        </property>
        <property name="currencyID" type="java.lang.Integer">
            <column name="CurrencyID" not-null="true" />
        </property>
        <property name="currencyRateTypeID" type="java.lang.Integer">
            <column name="CurrencyRateTypeID" not-null="true" />
        </property>
        <property name="useAliasFormat" type="java.lang.Boolean">
            <column name="RmaUseAliasFormat" />
        </property>
        <property name="aliasFormatID" type="java.lang.Integer">
            <column name="AliasFormatID" />
        </property>
        <set name="folderEntries" lazy="true" cascade="delete">
           <key column="rmaID" />
           <one-to-many class="com.eis.risk.analysis.FolderEntry"/>
        </set>
        <set name="latestPointLink" lazy="true" cascade="delete">
           <key column="rmaID" />
           <one-to-many class="com.eis.risk.analysis.LatestPointLink"/>
        </set>
        <set name="locks" lazy="true" cascade="delete">
           <key column="rmaID" />
           <one-to-many class="com.eis.risk.analysis.AnalysisLock"/>
        </set>
        <set name="statusPoints" lazy="true" cascade="delete">
           <key column="rmaID" />
           <one-to-many class="com.eis.risk.analysis.AnalysisStatusPoint"/>
        </set>
        <set name="riskEntries" lazy="true" cascade="delete">
           <key column="rmaID"/>
           <one-to-many class="com.eis.risk.entry.RiskEntryPlus"/>
        </set>
    </class>
</hibernate-mapping>


----oOo---


Top
 Profile  
 
 Post subject:
PostPosted: Sun Feb 03, 2008 6:52 am 
Regular
Regular

Joined: Tue Apr 10, 2007 10:02 am
Posts: 56
I've found the cause of the triple duplicate records.

It seems that whenever Hibernate executes a query against a mapped class it will also execute equivalent queries against any sub classes.

Hence if class 'A' has a sub class 'B', and a query is executed against class 'A' then Hibernate will also automatically execute the same query against class B as well.

In my original posting I stated that I had three classes where class 'B' and 'C' were sub classes of class 'A'. All three classes were linked to the same table. To test my findings I changed my mapings so that classes 'B' and 'C' were linked to a logical view rather than the same table as 'A'. No difference, even with the change in mappings the single query of class A effectively also executes at the same time an equivalent query on B and C.

From this you have to assume that class inheritance can't be used when considering how to retrieve composite objects. Instead I'll have to use aggregate objects that group distinct objects.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Feb 03, 2008 7:27 am 
Regular
Regular

Joined: Mon Aug 20, 2007 6:47 am
Posts: 74
Location: UK
Hi,

I think it's possible to do what you were originally trying to do. You are using the "Table per class hierarchy" strategy to map class inheritance, but you have not given hibernate enough information as far as I can tell.

You need to make sure Hibernate knows which rows in the table map to which java classes using a discriminator value or formula. Rather than waffle on about it, here's a link describing what must be done:

http://www.hibernate.org/hib_docs/reference/en/html/inheritance.html

After you follow those instrutions and edit your mapping xml for the Analysis class, I think you might have to modify your query as well. If you query for Analysis instances, I think you will still get all the different subclasses bundled in. If you only want instances of the subtype you should query "from AnalysisInfo", etc.

I hope that helps.

-Paul


Top
 Profile  
 
 Post subject:
PostPosted: Sun Feb 03, 2008 11:44 am 
Regular
Regular

Joined: Tue Apr 10, 2007 10:02 am
Posts: 56
The problem I was addressing wasn't about a hierarchy of persistable sub classes.

The main class 'a' is a simple entity which does have read/write operations. However, both sub classes 'b' and 'c' are read only representations of 'a' with extra data drawn from related object areas.

For example, if 'a' is an employee object, then 'b' might be an employee object with the employee address info appended as properties of class 'b'.

The usage scenario is straightforward enough. The 'a' class is employed for CRUD type data maintenance on entity 'a'; whilst 'b' is used in an information gathering capacity only.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Feb 03, 2008 12:14 pm 
Regular
Regular

Joined: Mon Aug 20, 2007 6:47 am
Posts: 74
Location: UK
But all those classes persist to the same table, right? From the mapping documents you posted I can't see how hibernate can ever know which java class to use for each row in the table "rma".

From that, I'm not at all surprised that you don't get the results you expect from your query.

Unless I've completely misunderstood your problem?


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 5 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.