Describe the feature
I've been trying to implement an M2M relationship on two models for the past two days now and have come to the conclusion that this feature does not work well with the Append method in GORM. The design decision to create a new record on Model B when calling Append on Model A with Model B's ID is mostly not useful primarily because "Append" implies an association of two existing records. Choosing to assume that both Records do not exist isn't the right approach because, in the real world, associations happen if both records exist. A new record should not be created on Model B when an association is made because the fundamental idea is that an association is made with two pieces of data that already exist in a practical/virtual form and not in a theoretical one.
Motivation
I encountered this issue while doing the following.
connection struct {
gorm.Model
ID string `gorm:"primaryKey"`
}
pipeline struct {
gorm.Model
ID string `gorm:"primaryKey"`
Name string
Slug string `gorm:"index"`
Description string
DecommissionedAt *time.Time
Descendants []connection `gorm:"many2many:pipelines_connections;joinForeignKey:parent_id;References:id;joinReferences:descendant_id"`
Parents []connection `gorm:"many2many:pipelines_connections;joinForeignKey:descendant_id;References:id;joinReferences:parent_id"`
}
In the above code "pipeline" is a model with many other connections, the connections are actually other pipelines and depending on the form of connection it can be the parent or the descendant. So in essence pipelines and connections may be separate models but they both use the same table. To achieve this relationship with the model we have a many-to-many relationship that properly depicts the pipeline Descendants and Parents stating the foreign keys and the reference keys.
Now after calling create on Pipeline A, I attempt appending Pipeline B (connection) by its ID like so.
result := tx.Session(&gorm.Session{Context: ctx}).Create(&model{
ID: input.ID,
Name: input.Name,
Slug: input.Slug,
Description: input.Description,
})
// append parents. input.Parents contains an array of connections. i.e. []connections
err := result.Association("Parents").Append(input.Parents)
if err != nil {
tx.Rollback()
return err
}
The above code first creates the new pipeline in the transaction and then when I call appends, instead of saving the relationship between pipeline and connection in an M2M table(pipelines_connections) it tries to create a new connection record in its table. The approach should be to create a record on the M2M relationship table depicting the association.
At least if the append method call should create new connections and not just store data in the M2M relationship, there should be a way to opt in or out of this behaviour maybe in the session config.
Related Issues
None