Wednesday, August 31, 2005
Bulk Insert in Hibernate 3.0.5
Bulk insert operation is a nice feature in that a single DML such as HQL or SQL will result in zero or multiple records inserted into a table. Unfortunately, Hibernate 3.0.5 does not yet support bulk insert operation, even though both bulk update and delete operations are supported. Since bulk insert is supposed to be supported in Hibernate 3.1, so I downloaded the latest 3.1beta2 release and tried. It didn't work.
So, how can we make bulk insert operations happen in Hibernate 3.0.5 ? Well here is a quick hack. Hibernate allows parameterized native SQL Query to be specified in the Hibernate mapping file via the <sql-query> XML element. So one obvious idea is to specify a native SQL Query with an INSERT statement. However, I couldn't get this to work without tweaking two classes:
Example:
Is this the smell of wet dog ? Hopefully the Hibernate team will provide proper support for HQL bulk insert operation in the near future. As requested, this hack has been submitted as a patch.
So, how can we make bulk insert operations happen in Hibernate 3.0.5 ? Well here is a quick hack. Hibernate allows parameterized native SQL Query to be specified in the Hibernate mapping file via the <sql-query> XML element. So one obvious idea is to specify a native SQL Query with an INSERT statement. However, I couldn't get this to work without tweaking two classes:
org.hibernate.loader.Loader.javaThe hibernate3.0.5-patched.jar can be used as a drop-in replacement of the hibernate3.jar as found in the 3.0.5 distribution.
org.hibernate.loader.custom.CustomLoader.java
Example:
<sql-query name="bulkInsertQuery1">
<return-scalar column="null" type="int"/>
insert into A (a1, a2, a3)
select b1, b2, :p1 from B
where b3 = :p2
</sql-query>
- The <return-scalar> is necessary to keep Hibernate 3.0.5 happy, so it won't reject the insert statement.
- The column="null" is a special notation recognized by the patched classes to simply execute the native SQL without bothering with the return value.
String[] paramNames = {"p1", "p2"};That's all. It's a hack but it works perfectly for executing any arbitrary native SQL!
Object[] paramValues = {"p1value", "p2value"};
// Execute the native SQL Query purely for it's side effect
getHibernateTemplate().findByNamedQueryAndNamedParam("bulkInsertQuery1", paramNames, paramValues);
Is this the smell of wet dog ? Hopefully the Hibernate team will provide proper support for HQL bulk insert operation in the near future. As requested, this hack has been submitted as a patch.
Monday, August 08, 2005
Accessing Default Namespace with XPath
I was wondering if there is a way in XPath to access XML elements specified with a default namespace. For example, here is an XML using namespace "ns1" and a default namespace:
Well, here is one that will do the job. The trick is simply to make use of the property that the local name of an element is equal to it's full name only if the element is in the default namespace.
How can we specify an XPath expression to access element C (in the default namespace) ? The naive solution:
<ns1:A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://hanson/Dadidadida">
xmlns:ns1="http://hanson/Dadidadida/ns1"
>
<ns1:B><C/></ns1:B>
</ns1:A>
/ns1:A/ns1:B/Cwon't work. Many places (such as this) seem to indicate that there is just no way to do it. But is that really the case ?
Well, here is one that will do the job. The trick is simply to make use of the property that the local name of an element is equal to it's full name only if the element is in the default namespace.
/ns1:A/ns1:B/*[local-name()=name()][name()='C']or simply,
/ns1:A/ns1:B/*[name()='C']Why XPath doesn't have something simpler is beyond me.
Friday, August 05, 2005
Beanlib 2.4.1
Bealib 2.4.1 is now available for download from sourceforge. This is an enhancement release supporting customization of the Hibernate Bean Transformation process via the CustomHibernateBeanTransformable interface.
You can now selectively override the default transformation behavior by plugging in your own implementation of this interface to the HibernateBeanReplicator via the initCustomTransformer method.
A sample usage to handle the JDK1.5 enum can be found in the JUnit test here.
You can now selectively override the default transformation behavior by plugging in your own implementation of this interface to the HibernateBeanReplicator via the initCustomTransformer method.
A sample usage to handle the JDK1.5 enum can be found in the JUnit test here.