hibernatenetbeansderbypojohbmxml

NetBeans > Hibernate Wizards > Create POJOs from database" (Derby) does not generate any relationship-mappings in hbm.xml


I'm generating POJO from Derby 10.14.2.0 database in NetBeans IDE 11.3, Hibernate ORM 5.4.31.

It does not generate any relationship-mappings in hbm.xml or in entity classes like many-to-one/one-to-one).

I used Derby sample project for mcve.

I've used two tables from Derby sample database.

Product and PurchaseOrder

Product table is referenced in PurchaseOrder.

Table PurchaseOrder has FOREIGN_KEY_PRODUCT_ID. can see in image below.

enter image description here

hibernate.cfg

<hibernate-configuration>
    <session-factory>
        <property name="hibernate.dialect">org.hibernate.dialect.DerbyTenSevenDialect</property>
        <property name="hibernate.connection.driver_class">org.apache.derby.jdbc.ClientDriver</property>
        <property name="hibernate.connection.url">jdbc:derby://localhost:1527/sample</property>
        <property name="hibernate.connection.username">app</property>
        <property name="hibernate.connection.password">app</property>
       
        <mapping resource="com/pojo/Product.hbm.xml"/>
        <mapping resource="com/pojo/PurchaseOrder.hbm.xml"/>
    </session-factory>
</hibernate-configuration>  

I also tried defining hibernate properties

<property name="hibernate.default_catalog">app</property>

and

<property name="hibernate.default_schema">app</property>  

But no, it won't help.

hibernate.reveng.xml

<hibernate-reverse-engineering>
  <schema-selection match-schema="APP"/>
  <table-filter match-name="PRODUCT"/>
  <table-filter match-name="PURCHASE_ORDER"/>
</hibernate-reverse-engineering>

PurchaseOrder.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="com.pojo.PurchaseOrder" table="PURCHASE_ORDER" schema="APP" optimistic-lock="version">
        <id name="orderNum" type="int">
            <column name="ORDER_NUM" />
            <generator class="assigned" />
        </id>
        <property name="customerId" type="int">
            <column name="CUSTOMER_ID" not-null="true" />
        </property>
        <property name="productId" type="int">
            <column name="PRODUCT_ID" not-null="true" />
        </property>
        <property name="quantity" type="java.lang.Short">
            <column name="QUANTITY" />
        </property>
        <property name="shippingCost" type="big_decimal">
            <column name="SHIPPING_COST" precision="12" />
        </property>
        <property name="salesDate" type="date">
            <column name="SALES_DATE" length="10" />
        </property>
        <property name="shippingDate" type="date">
            <column name="SHIPPING_DATE" length="10" />
        </property>
        <property name="freightCompany" type="string">
            <column name="FREIGHT_COMPANY" length="30" />
        </property>
    </class>
</hibernate-mapping>  

In above PurchaseOrder.hbm.xml file, relationship mapping should be generated but you can see it is missing.

Why relationship mapping doesn't generating even for sample database of Derby?

With MySQL it is working fine.

Doesn't Hibernate support Derby properly?
What is solution?


Solution

  • The short answer

    You were close to solving it. The short answer is: just add this line to your hibernate.cfg.xml config file (add empty catalog):

    <property name="hibernate.default_catalog"/>
    

    My hibernate.cfg.xml looks like this:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
    <hibernate-configuration>
      <session-factory>
        <property name="hibernate.dialect">org.hibernate.dialect.DerbyDialect</property>
        <property name="hibernate.connection.driver_class">org.apache.derby.jdbc.ClientDriver</property>
        <property name="hibernate.connection.url">jdbc:derby://localhost:1527/sample</property>
        <property name="hibernate.connection.username">app</property>
        <property name="hibernate.connection.password">app</property>
        <property name="hibernate.default_catalog"/>
      </session-factory>
    </hibernate-configuration>
    

    With this configuration, the NetBeans Hibernate POJO wizard generates relationship mappings nicely. See the generated PurchaseOrder.hbm.xml file:

    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    <!-- Generated 13.06.2021 12:06:13 by Hibernate Tools 4.3.1 -->
    <hibernate-mapping>
        <class name="pojo.PurchaseOrder" table="PURCHASE_ORDER" schema="APP" optimistic-lock="version">
            <id name="orderNum" type="int">
                <column name="ORDER_NUM" />
                <generator class="assigned" />
            </id>
            <many-to-one name="customer" class="pojo.Customer" fetch="select">
                <column name="CUSTOMER_ID" not-null="true" />
            </many-to-one>
            <many-to-one name="product" class="pojo.Product" fetch="select">
                <column name="PRODUCT_ID" not-null="true" />
            </many-to-one>
            <property name="quantity" type="java.lang.Short">
                <column name="QUANTITY" />
            </property>
            <property name="shippingCost" type="big_decimal">
                <column name="SHIPPING_COST" precision="12" />
            </property>
            <property name="salesDate" type="date">
                <column name="SALES_DATE" length="10" />
            </property>
            <property name="shippingDate" type="date">
                <column name="SHIPPING_DATE" length="10" />
            </property>
            <property name="freightCompany" type="string">
                <column name="FREIGHT_COMPANY" length="30" />
            </property>
        </class>
    </hibernate-mapping>
    

    The long answer

    Just for clarification, the NetBeans 11.3 POJO wizard uses the following versions of hibernate:

    The NetBeans wizard uses these libraries for the generation of POJO from databases. The basic workflow is:

    1. Get all tables from the database, it uses the method getTables of DatabaseMetaData
    2. Create a list of a fully qualified name of all tables. A fully qualified name is the name of a table in the form [catalog].[schema].[table]. The Derby database returns an empty string (not null but empty ) for the catalog parameter. Hibernate nicely handle it, but we can see that different databases behave differently here. As you can see here there is even comment about it.
    3. After step 2 we have a Map collection of all tables with keys like APP.CUSTOMER, APP.PRODUCT etc. So far, so good.
    4. Hibernate gets all foreign keys for a particular table, for example, APP.CUSTOMER using getExportedKeys method.
    5. Hibernate tools tries to form a fully qualified name of a table again in the form [catalog].[schema].[table] but this time not so nicely and it ends up with the table name .APP.CUSTOMER (see the dot before app). See here. The qualify method checks for the catalog!=null but getExportedKeys returns it as empty string not null.
    6. Hibernate tools tries to map the table from the foreign keys with the Map, created at the step 3 and fails (because of the dot).

    The workaround works because we say to the Hibernate that catalog is not null but empty. See this lines.

    Conclusion

    So the reason Hibernate doesn't work with derby because the derby JDBC client behaves differently when returning info about foreign keys. It returns an empty string for the catalog parameter but MySQL apparently returns null.

    The hibernate orm framework has special treatment for this case when parsing info about tables but lacks it when working with foreign keys. So I suppose it could be considered a bug in Hibernate tools 4.3.1