Mapping Inheritance to Relational Databases
Inheritance is the key concept of object-oriented programming.
A subclass is basically inherits the properties of its parent class.
Let’s say, for our application we define basic class User
.
We need also Customer
and Maintainer
classes as a custom type of User
,
so we inherit them from the super class.
Customer
and Maintainer
subclasses, which are inherited from User
,
have username
and password
fields as common but also some additional specific fields.
When we want to store those objects into a relational database system,
they need to be mapped as tables.
However, relational databases don’t support inheritance.
In this example we have one base class and two subclasses to map into the relational database as tables.
There are three approaches with their trade-offs to do that.
1) Single table
User table:
id | username | password | customerNumber | employeeNumber | type |
---|---|---|---|---|---|
1 | Alice | 123 | 10001 | NULL | Customer |
2 | Bob | abc | NULL | 10001 | Maintaner |
In this approach, all fields, which are defined under a super (parent) class, are stored in a single table.
It is easy to query and retrieve different types from one table without need of join statements.
However, a query to get Customer
class object would also return irrelevant employeeNumber
field;
hence all regarding fields should be specified in the select statement.
Another problem is that, it is not possible to use constrains such as not null for a subclass.
For example, customerNumber
is an essential field for all Customer
records.
Yet applying not null constrain for customerNumber
would prevent us from storing other objects without customerNumber
such as Maintainer
.
2) Class Table Inheritance
User table
id | username | password | type |
---|---|---|---|
1 | Alice | 123 | Customer |
2 | Bob | abc | Maintaner |
Customer table
id | customerNumber |
---|---|
1 | 10001 |
Maintainer table
id | employeeNumber |
---|---|
2 | 10001 |
In this approach, there exist one database table per class.
Separate tables provide consistent data storage with constrain definitions but it is more complex to query a subclass.
It requires to write some join statements which reduces the performance.
For example, to get a Customer
object, it needs to be join with User
table.
3) Concrete Table Inheritance
Customer table
id | username | password | customerNumber |
---|---|---|---|
1 | Alice | 123 | 10001 |
Maintainer table
id | username | password | employeeNumber |
---|---|---|---|
2 | Bob | abc | 10001 |
In this approach, there exist a table for each concrete class.
Every concrete class has a table with duplicated fields.
In case of updating a field type of the base class would require to migrate multiple tables.
For example, if we change character size of password
field, we need to alter both Maintaner
and Customer
tables.
It might lead a conflict.