Your Question

Gorm homepage explains that it has support for single-table inheritance. But it has not been mentioned how to implement it in Association section of the doc

The document you expected this should be explained

I expect it to be mentioned in Association section of the doc

Expected answer

Comment From: ChaminW

Any updates on this question? Is there any unofficial guide I can follow for the implementation since official documentation does not include it?

Comment From: leandrorebelo

Is there some doc about this?

Comment From: ldaverio

I'm also interested in the answer, and/or a working example :)

Comment From: abferm

Also interested in how to do this. We have several polymorphic types we would like to store using single table inheritance.

Comment From: JokerCatz

I know how to write Ruby / Rails / Golang , and I think this is easy way to like

type Animal struct {
  gorm.Model
  Type      string // Rails.ActiveRecord reserved word , it mean real model name , like "Animal" / "Cat" / "Dog"

  // same as belongs_to   (self has target ID)
  ParentID  int64
  Parent    Animal `gorm:"foreignKey:ParentID"`

  // same as has_many     (target table has my ID)
  Childs  []Animal `gorm:"foreignKey:ParentID"`
}
type Cat struct {
  // same as Animal struct , dont change Animal to Cat
}
type Dog struct {
  // same as Animal struct , dont change Animal to Dog
}

// every model use same table name
func (Animal) TableName() string {return "dittos"}
func (Cat   ) TableName() string {return "dittos"}
func (Dog   ) TableName() string {return "dittos"}

and Animal need write some code to redirect to (or deep copy) current model / struct , like

animal.Is("Dog") => return bool
animal.GetReal() => return "Dog" , interface{}(Dog{})

and sorry , code is not tested , just show how to made it

Comment From: atheken

Would it be possible to get a reference in the gorm code for how STI is supported? If I could locate how/when type discriminators were defined, I could probably work through and provide an example. Thanks for all the work you've put into this module over the years.

Comment From: yoavke

I have recently begun reading the documentation, and while going through the overview page, I noticed a reference to 'Single-table inheritance' that piqued my curiosity. I need it for a project I am currently working on. I searched for a page that explains how it works in GORM, but I couldn't find any relevant information. As a result, I decided to Google it and came across this thread.

Could it be possible that GORM does not currently support Single-table inheritance?

Comment From: rafikiassumani

Is there any progress on this? Do you mind providing a working example @jinzhu ?

Comment From: GabrielRabello

I will use the same example @JokerCatz used, but keep in mind I implemented it with success using entities with more data:

// Single table inheritance
type Animal struct { // Common fields 
  gorm.Model
  Type int  // I used an application-managed enum. You could use a string or an FK to a lookup table
  // other common fields...
}

// Note that this is the only place I will implement the Tabler interface.
func (a *Animal) TableName() string {
    return "animal"
}

type Cat struct {
// Since this is an embedded struct, Cat automatically implements the Tabler interface implemented by Animal, therefore Gorm will use the same table.
  Animal 
  // Cat fields
}

const catType = 1

func NewCat() *Cat {
  return &Cat{Animal: Animal{Type: catType}}
}

type Dog struct {
  Animal
  // Dog fields
}

const dogType = 2

func NewDog() *Dog {
  return &Dog{Animal: Animal{Type: dogType}}
}

Implemented that way, you will have multiple structs, where you can implement separate logic while having one single table to store all your data.

As a bonus, I've just implemented a table per class strategy, not sure yet how well it will perform for more advanced uses (only tested creation and update so far). Since the Gorm docs don't mention it, I'm not sure if it was an oversight or if I will hit a brick wall eventually, but there you go:

// Table per class inheritance
type Animal struct { // That's the "super table"
  gorm.Model
  weight float
  // other common fields...
}

func (a *Animal) TableName() string {
    return "animal"
}

// For creation all you need is to generate the id of the super table. Gorm will figure out the rest
func (a *Animal) BeforeCreate(tx *gorm.DB) error {
  if a.ID == 0 {
    a.ID = NewId() // Something to get your id
  }
}

type Cat struct {
 AnimalId uint64 `gorm:"primaryKey"`
 Animal Animal `gorm:"foreignKey:AnimalId"`
 // Cat fields...
}

func (c *Cat) TableName() string {
  return "cat" // the cat table
}

type Dog struct {
 AnimalId uint64 `gorm:"primaryKey"`
 Animal Animal `gorm:"foreignKey:AnimalId"`
 // Dog fields
}

func (d *Dog) TableName() string {
  return "dog" // the dog table
}

Populating the common fields may be awkward when sending a request for a child entity, so I recommend using a DTO with denormalized data to then create your entity.

Note that you don't need to assign an ID for the child table when creating or updating one. You can assign it to the parent and Gorm will figure out that it is the same key.

And since the parent table is an association, if you want to update it when updating the child table, you need to update with associations (ex: db.Session(&gorm.Session{FullSaveAssociations: true}).Updates(&cat)).

Hope I helped and I'm sorry for any grammar mistakes.