TL;DR How can I enforce the Hibernate schema creation to create a foreign key constraint in a table-per-concrete-class setup from AbstractProperty.ownerId
to Owner.ownerId
for the structure displayed below, without adding a Owner
property to the AbstractProperty
?
I'm working on a project where I have the following class structure:
The Owner
has a one-to-one mapping to an AbstractProperty
, which is extended by the ConcreteProperty
class (and others like AnotherProperty
, but that's not really relevant for the rest of this question).
The AbstractProperty
really has only one property, the abstractPropertyId
. Therefor, we want to use the table-per-concrete-class structure, ending up with the tables Owner
, ConcreteProperty
, and tables for the other AbstractProperty
extending classes (AnotherProperty
).
To this end, I created the following mapping for Owner
:
<?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 package="com.example"> <class name="Owner"> <id name="ownerId"> <generator class="identity"/> </id> <property name="ownerProperty"/> <one-to-one name="abstractProperty"/> </class> </hibernate-mapping>
And for the AbstractProperty
:
<?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 package="com.example"> <class name="AbstractProperty" abstract="true"> <id name="ownerId"> <generator class="foreign"> <param name="property">ownerId</param> </generator> </id> <union-subclass name="ConcreteProperty"> <property name="concreteProperty"/> </union-subclass> <union-subclass name="AnotherProperty"> <property name="anotherProperty"/> </union-subclass> </class> </hibernate-mapping>
This works.
However, and here is my question, using this mapping and having Hibernate create the schema for me (<property name="hbm2ddl.auto">create</property>
), it does not create a foreign key constraint from the ConcreteProperty.ownerId
database field to the Owner.ownerId
field. It does when I create the inverse constrained one-to-one field from the AbstractProperty
to Owner
using this mapping for AbstractProperty
(where the owner
field is of type Owner
in the AbstractProperty
java class):
<?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 package="com.example"> <class name="AbstractProperty" abstract="true"> <id name="ownerId"> <generator class="foreign"> <param name="property">ownerId</param> </generator> </id> <one-to-one name="owner" constrained="true"/> <union-subclass name="ConcreteProperty"> <property name="concreteProperty"/> </union-subclass> <union-subclass name="AnotherProperty"> <property name="anotherProperty"/> </union-subclass> </class> </hibernate-mapping>
How can I enforce the creation of a foreign key from AbstractProperty.ownerId
to Owner.ownerId
without this Owner
field in my AbstractProperty
?
A table with a foreign key reference to itself is still limited to 253 foreign key references. Greater than 253 foreign key references are not currently available for columnstore indexes, memory-optimized tables, Stretch Database, or partitioned foreign key tables.
There is no problem having a table that consists of foreign keys only. In your particular example it would be OK to remove the OrderID. Relational theory states that each table should have a candidate key so, ideally, the business rule you mention would be in place to make the foreign key only table a "good" table.
Note that foreign keys are not mandatory, and a table may have no foreign keys. Conversely, every column in a table may have a foreign key constraint.
A table can have multiple foreign keys based on the requirement.
Simple answer: Never let Hibernate create the schema for real applications.
Hibernate is an object relational mapper and one should treat it as this.
That Hibernate additionally creates schemas is at most kind for the first time. But in environments after the first release you don't want to have Hibernate control over the schema. After all you have to handle SQL to have migrations scripts (manually or tool support). After the first release you will have data in the database. To ensure data migration on the production system with less problems you should consider schema and data migration the same way in the production environment as you do in your development environment.
Exceptions of that can be any application that has rarely changing data that may be reconstructable fast on data loss.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With