3,2,4,GA
I am having a problem with a polymorphic association in dynamic-map mode. I have the following structure:
Document.get( "lines" ) is a one-to-many to DocumentLine's
BidDocument extends Document
BidDocument.get( "lines" ) is a one-to-many to BidDocumentLine's
I declare the association in Document using the following:
Code:
<set name="lines" inverse="true" cascade="all-delete-orphan" lazy="true">
<key column="document_id"/>
<one-to-many entity-name="DocumentLine"/>
</set>
And the inverse relation in DocumentLine
Code:
<many-to-one name="document" column="document_id" entity-name="Document" lazy="proxy"/>
There is no corresponding association in BidDocument or BidDocumentLine.
I populate a BidDocument with BidDocumentLines and then persist the BidDocument. All the BidDocument related information is persisted to the hierarchy just fine, but the BidDocumentLines are persisted as DocumentLines. IE: There is a row created for each DocumentLine, but no rows in the BidDocumentLine table.
I have tried <joined-subclass> as well as <subclass><join> with a discriminator but no avail, same problem.
I have tried to set the $type$ key on the map to see if that will help but when looking at the source code it seems that key is only used to indicate the type before passing it to the user, not to determine at runtime how to persist the map (like an implicit discriminator maybe?)
Can I override a method in the EntityPersister to force hibernate to persist the Map as a specific entity-name? Or how can I get the desired behavior without doing this? I would like to use <joined-subclass> if possible
Mapping documents and code follow:
Document.hbm.xml
Code:
<hibernate-mapping>
<joined-subclass entity-name="Document" extends="Base" table="document">
<tuplizer class="org.hibernate.tuple.entity.HibernateEntityMapTupilizer"
entity-mode="dynamic-map"/>
<key column="id"/>
<property name="name" type="string" column="name"/>
<property name="companyName" type="string" column="company_name"/>
<property name="reference" type="string" column="reference"/>
<property name="customerReference" type="string" column="customer_reference"/>
<property name="created" type="timestamp" column="created"/>
<property name="modified" type="timestamp" column="modified"/>
<property name="description" column="description" type="text"/>
<many-to-one name="category" column="category_id" entity-name="Category" lazy="proxy"/>
<many-to-one name="createdBy" column="employee_created_by_id" entity-name="Employee" lazy="proxy"/>
<many-to-one name="modifiedBy" column="employee_modified_by_id" entity-name="Employee" lazy="proxy"/>
<set name="lines" inverse="true" cascade="all-delete-orphan" lazy="true">
<key column="document_id"/>
<one-to-many entity-name="DocumentLine"/>
</set>
</joined-subclass>
</hibernate-mapping>
DocumentLine.hbm.xml
Code:
<hibernate-mapping>
<joined-subclass entity-name="DocumentLine" extends="Base" table="document_line">
<tuplizer class="org.hibernate.tuple.entity.HibernateEntityMapTupilizer"
entity-mode="dynamic-map"/>
<key column="id"/>
<many-to-one name="document" column="document_id" entity-name="Document" lazy="proxy"/>
</joined-subclass>
</hibernate-mapping>
Bid.hbm.xml
Code:
<hibernate-mapping>
<joined-subclass entity-name="Bid" extends="Document" table="bid">
<key column="id"/>
</joined-subclass>
</hibernate-mapping>
BidLine.hbm.xml
Code:
<hibernate-mapping>
<joined-subclass entity-name="BidLine" extends="DocumentLine" table="bid_line">
<tuplizer class="org.hibernate.tuple.entity.HibernateEntityMapTupilizer"
entity-mode="dynamic-map"/>
<key column="id"/>
<property name="manufacturerSKU" type="string" column="manufacturer_sku"/>
<property name="ediSKU" type="string" column="edi_sku"/>
<property name="bidPrice" type="double" column="bid_price"/>
<property name="askPrice" type="double" column="ask_price"/>
<property name="quantity" type="integer" column="quantity"/>
<property name="description" type="string" column="description"/>
</joined-subclass>
</hibernate-mapping>
HibernateEntityMapTuplizer.java
Code:
public class HibernateEntityMapTupilizer extends DynamicMapEntityTuplizer
{
private static Log log = LogFactory.getLog(HibernateEntityMapTupilizer.class);
public HibernateEntityMapTupilizer( EntityMetamodel entityMetamodel, PersistentClass persistentClass )
{
super(entityMetamodel, persistentClass);
}
protected Instantiator buildInstantiator( final PersistentClass persistentClass )
{
return new DynamicMapInstantiator( persistentClass ) {
protected Map generateMap()
{
return new Entity( persistentClass.getEntityName() );
}
};
}
public Class getMappedClass()
{
return Entity.class;
}
}
main()
Code:
SessionFactory sf = (SessionFactory)context.getBean( "sessionFactory" );
Session session = sf.openSession();
Transaction tx = session.beginTransaction();
Entity bid = new Entity( "Bid" );
bid.put( "name", "Bid Document #1" );
Entity bidLine = new Entity( "BidLine" );
bidLine.put( "description", "Product #1" );
List list = new ArrayList( );
list.add( bidLine );
bid.put( "lines", list );
bidLine.put( "document", bid );
session.merge( "SonyBid", bid );
tx.commit();
System.out.println("Finished.");
Here is the log output:
Code:
DEBUG SQL - insert into document (name, company_name, reference, customer_reference, created, modified, description, category_id, employee_created_by_id, employee_modified_by_id, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into document (name, company_name, reference, customer_reference, created, modified, description, category_id, employee_created_by_id, employee_modified_by_id, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
DEBUG AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
DEBUG AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
DEBUG SQL - insert into bid (id) values (?)
Hibernate: insert into bid (id) values (?)
DEBUG AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
DEBUG AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
DEBUG SQL - insert into bid_sony (sony1, sony2, id) values (?, ?, ?)
Hibernate: insert into bid_sony (sony1, sony2, id) values (?, ?, ?)
DEBUG AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
DEBUG AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
DEBUG SQL - insert into base (version, id) values (?, ?)
Hibernate: insert into base (version, id) values (?, ?)
DEBUG AbstractBatcher - Executing batch size: 1
DEBUG AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
DEBUG AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
DEBUG SQL - insert into document_line (document_id, id) values (?, ?)
Hibernate: insert into document_line (document_id, id) values (?, ?)
DEBUG AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
DEBUG AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
DEBUG SQL - update base set version=? where id=? and version=?
Hibernate: update base set version=? where id=? and version=?
DEBUG AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
DEBUG JDBCTransaction - re-enabling autocommit
DEBUG JDBCTransaction - committed JDBC Connection
DEBUG ConnectionManager - transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!
Finished.
And finally, the SQL results:
Code:
erp=> select * from document;
id | name | company_name | reference | customer_reference | created | modified | description | category_id | employee_created_by_id | employee_modified_by_id
----+-----------------+--------------+-----------+--------------------+---------+----------+-------------+-------------+------------------------+-------------------------
1 | Bid Document #1 | | | | | | | | |
(1 row)
erp=> select * from document_line;
id | document_id
----+-------------
2 | 1
(1 row)
erp=> select * from bid;
id
----
1
(1 row)
erp=> select * from bid_line;
id | manufacturer_sku | edi_sku | bid_price | ask_price | quantity | description
----+------------------+---------+-----------+-----------+----------+-------------
(0 rows)
On another side note: why is DynamicMapEntityTuplizer package protected?
Hope this is enough information. I think it is just something stupid in my mapping files, but I can't seem to figure out what.