Single Table Inheritance
Single Table Inheritance commonly known as STI is a design pattern used in object-oriented programming where a single database table is used to store multiple types of related objects that share common attributes.
The relational databases don't inherently support inheritance. However, STI is a technique used to represent a hierarchy of classes within a single table. You might ask, why use a single table? The answer lies in optimizing data retrieval. When data is spread across multiple tables, the process of joining records from different tables introduces overhead, making it less efficient to retrieve the desired data.
Let's understand with an example using books in Ruby on Rails.
Suppose we have two types of books Fiction
and Non-Fiction
. They share common attributes like title
and price
, but they also have some specific attributes like Fiction
has genre
and Non-Fiction
has plot
.
Relational (Postgres)
- Create a table
books
create_table :books do |t|
t.string :title
t.float :price
t.string :type # This column stores the class name for STI
t.string :genre # Specific attribute for Fiction books
t.string :plot # Specific attribute for Non-Fiction books
t.timestamps
end
- Create a model
Book
, it will be the base model for STI.
class Book < ApplicationRecord
end
- Create two subclasses as per example
FictionBook
andNonFictionBook
class FictionBook < Book
validates :genre, presence: true
end
class NonFictionBook < Book
validates :plot, presence: true
end
- Usage
fiction_book = FictionBook.create(title: "The Great Gatsby", price: 19.99, genre: "Classic")
non_fiction_book = NonFictionBook.create(title: "Sapiens", price: 24.99, plot: "Twist")
# Retrieve all books
all_books = Book.all
# Retrieve only fiction books
fiction_books = FictionBook.all
# Retrieve only non-fiction books
non_fiction_books = NonFictionBook.all
Non-Relational (MongoDb)
- Create a model
Book
, it will be the base model for STI.
class Book
include Mongoid::Document
field :title, type: String
field :price, type: Float
field :type, type: String # This field stores the class name for STI
end
- Create two subclasses as per example
FictionBook
andNonFictionBook
class FictionBook < Book
field :genre, type: String
end
class NonFictionBook < Book
field :plot, type: Integer
end
- Usage
fiction_book = FictionBook.create(title: "The Great Gatsby", price: 19.99, genre: "Classic")
non_fiction_book = NonFictionBook.create(title: "Sapiens", price: 24.99, plot: "Twist")
# Retrieve all books
all_books = Book.all
# Retrieve only fiction books
fiction_books = FictionBook.all
# Retrieve only non-fiction books
non_fiction_books = NonFictionBook.all
The NoSQL databases (MongoDb) doesn't strictly enforce a fixed schema. This flexibility allows you to store documents with different structures in the same collection, which is the underlying concept behind Single Table Inheritance.
Q: You might also ask is how the type
field is populated?
A: When a table has a column named type
, active record or mongoid will enable STI and add the class name
to the type
field, that is how the dots get connected.
PUN: Question is if there are no tables in MongoDb should we still call it STI?
|-->