Here is my problem. I have a persistent collection (a sorted set) of RecordCountedItems within my Record object (see my mapping doc below). I am getting duplicate entries in my TaBRecordCountedItem table. I am not even calling save or update; the insertions happen when I call query.list(). I am possibly seeing this behavior so far as I can tell because of the sorting happening to the set when its loaded. I see that the collection is marked a dirty from the Hibernate debug trace and I see the 'insert into TaBRecordCountedItem' SQL statement output.
Side note: As you might see from my comment in the finally block I do not open and close my session with each load because I want to get the most bang for my caching buck; I have tied the session lifecycle to my HttpSession's lifecycle (its a struts webapp) because my HttpSessions are short-lived due to the nature of my app. As a result query.list() will potentially get called 2 or more times in the same session. Can this have anything to do with it? I have my suspicions but the sorting of the collection seems more probable.
Your help would be very appreciated!
Hibernate version:2.1.6
Mapping documents:
Code:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping>
<class name="com.century.tab.hibernate.Record" table="TaBRecord">
<cache usage="nonstrict-read-write"/>
<id column="Rec_Id" name="recId" type="long">
<generator class="native"/>
</id>
<property column="Rec_TimeIn" name="recTimeIn" type="timestamp"/>
<property column="Rec_TimeOut" name="recTimeOut" type="timestamp"/>
<property column="Rec_Comments" length="500" name="recComments" type="string"/>
<many-to-one name="employee" class="com.century.tab.hibernate.Employee" column="Emp_Id" not-null="true" outer-join="auto" />
<many-to-one name="function" class="com.century.tab.hibernate.Function" column="Func_Id" not-null="true" outer-join="auto" />
<set name="countedItems" table="TaBRecordCountedItem" sort="com.century.tab.util.RCIComparator" lazy="true" >
<key column="Rec_Id"/>
<composite-element class="com.century.tab.hibernate.RecordCountedItem" >
<property name="beginCnt" column="RCI_BeginCnt" type="java.lang.Double" />
<property name="endCnt" column="RCI_EndCnt" type="java.lang.Double" />
<many-to-one name="countedItem" column="CI_Id" class="com.century.tab.hibernate.CountedItem" />
</composite-element>
</set>
</class>
</hibernate-mapping>
Code between sessionFactory.openSession() and session.close():Code:
/**
* <code>selectAllRecordsForEmployeeTimesheet</code>
* @param httpSession
*
* @return
* @throws Exception
*/
public List selectAllRecordsForEmployeeTimesheet(HttpSession httpSession) throws Exception {
Session session = HibernateUtil.getInstance().reuseOrOpenNewHibernateSession(httpSession);
try {
Query query = session.createQuery("from Record R left join fetch R.countedItems where R.recTimeOut not is null ");
// +
// "order by R.employee.person.persLastName, R.employee.person.persFirstName, " +
// "R.recTimeIn, R.recTimeOut, R.function.job.jobNum, R.function.fdWithRate.functionDescription.fdCode");
Set recs = new TreeSet(new EmployeeTimesheetRecordComparator());
recs.addAll(query.list());
return new ArrayList(recs);
}
finally {
// no need to call session.close(), will be closed during session cleanup
}
}
Full stack trace of any exception that occurs:n/a
Name and version of the database you are using:SQL Server 2000
The generated SQL (show_sql=true):Code:
Hibernate: insert into TaBRecordCountedItem (Rec_Id, RCI_BeginCnt, RCI_EndCnt, CI_Id) values (?, ?, ?, ?)
Hibernate: insert into TaBRecordCountedItem (Rec_Id, RCI_BeginCnt, RCI_EndCnt, CI_Id) values (?, ?, ?, ?)
Hibernate: insert into TaBRecordCountedItem (Rec_Id, RCI_BeginCnt, RCI_EndCnt, CI_Id) values (?, ?, ?, ?)
Hibernate: select record0_.Rec_Id as Rec_Id, record0_.Rec_TimeIn as Rec_TimeIn, record0_.Rec_TimeOut as Rec_Time3_, record0_.Rec_Comments as Rec_Comm4_, record0_.Emp_Id as Emp_Id, record0_.Func_Id as Func_Id, countedite1_.Rec_Id as Rec_Id__, countedite1_.RCI_BeginCnt as RCI_Begi2___, countedite1_.RCI_EndCnt as RCI_EndCnt__, countedite1_.CI_Id as CI_Id__ from TaBRecord record0_ left outer join TaBRecordCountedItem countedite1_ on record0_.Rec_Id=countedite1_.Rec_Id where (record0_.Rec_TimeOut is not null )
Debug level Hibernate log excerpt:Code:
...
17:42:46,904 DEBUG Configuration:1012 - null<-org.dom4j.tree.DefaultAttribute@7bd46a [Attribute: name resource value "com/century/tab/hibernate/Record.hbm.xml"]
17:42:46,904 INFO Configuration:331 - Mapping resource: com/century/tab/hibernate/Record.hbm.xml
17:42:46,914 DEBUG DTDEntityResolver:20 - trying to locate http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd in classpath under net/sf/hibernate/
17:42:46,914 DEBUG DTDEntityResolver:29 - found http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd in classpath
17:42:46,924 INFO Binder:229 - Mapping class: com.century.tab.hibernate.Record -> TaBRecord
17:42:46,924 DEBUG CacheFactory:32 - cache for: com.century.tab.hibernate.Record usage strategy: nonstrict-read-write
17:42:46,934 DEBUG Binder:486 - Mapped property: recId -> Rec_Id, type: long
17:42:46,934 DEBUG Binder:486 - Mapped property: recTimeIn -> Rec_TimeIn, type: timestamp
17:42:46,934 DEBUG Binder:486 - Mapped property: recTimeOut -> Rec_TimeOut, type: timestamp
17:42:46,934 DEBUG Binder:486 - Mapped property: recComments -> Rec_Comments, type: string
17:42:46,934 DEBUG Binder:486 - Mapped property: employee -> Emp_Id, type: com.century.tab.hibernate.Employee
17:42:46,944 DEBUG Binder:486 - Mapped property: function -> Func_Id, type: com.century.tab.hibernate.Function
17:42:46,944 INFO Binder:571 - Mapping collection: com.century.tab.hibernate.Record.countedItems -> TaBRecordCountedItem
17:42:46,954 DEBUG Binder:486 - Mapped property: countedItems, type: java.util.SortedSet
...
17:42:47,185 DEBUG Binder:1353 - Second pass for collection: com.century.tab.hibernate.Record.countedItems
17:42:47,195 DEBUG Binder:486 - Mapped property: beginCnt -> RCI_BeginCnt, type: double
17:42:47,205 DEBUG Binder:486 - Mapped property: endCnt -> RCI_EndCnt, type: double
17:42:47,205 DEBUG Binder:486 - Mapped property: countedItem -> CI_Id, type: com.century.tab.hibernate.CountedItem
17:42:47,705 DEBUG Binder:1368 - Mapped collection key: Rec_Id, element: RCI_BeginCnt, RCI_EndCnt, CI_Id, type: com.century.tab.hibernate.RecordCountedItem
...
[b]<comment>I call query.list() here and sort and then in a while I call it again. When I do I get insertions like below:</comment>[/b]
Hibernate: insert into TaBRecordCountedItem (Rec_Id, RCI_BeginCnt, RCI_EndCnt, CI_Id) values (?, ?, ?, ?)
Hibernate: insert into TaBRecordCountedItem (Rec_Id, RCI_BeginCnt, RCI_EndCnt, CI_Id) values (?, ?, ?, ?)
Hibernate: insert into TaBRecordCountedItem (Rec_Id, RCI_BeginCnt, RCI_EndCnt, CI_Id) values (?, ?, ?, ?)
Hibernate: insert into TaBRecordCountedItem (Rec_Id, RCI_BeginCnt, RCI_EndCnt, CI_Id) values (?, ?, ?, ?)
Hibernate: insert into TaBRecordCountedItem (Rec_Id, RCI_BeginCnt, RCI_EndCnt, CI_Id) values (?, ?, ?, ?)