I use a postgres database and naming strategy
schema.NamingStrategy{
NoLowerCase: true,
SingularTable: true,
}
and have a database model like this:
type Project struct {
gorm.Model
UserID uint `gorm:"not null"`
User User
}
type Bar struct {
gorm.Model
ProjectID uint `gorm:"not null"`
Project Project
Foos []*Foo `gorm:"many2many:Bar_Foos;"`
}
type Foo struct {
gorm.Model
Bars []*Bar `gorm:"many2many:Bar_Foos;"`
ProjectID uint `gorm:"not null"`
Project Project
}
There is a many-to-many relationship between Foo
and Bar
. I want to show the user all of his Foos after he has selected a Bar. That is, I want to query for exactly those Foos where Foo.Bar.Project.UserID = $userId
and Foo.Bar.ID = $barId
. $userId
and $barId
are given in from outside.
I know that with TypeORM, this would be modeled using inner joins. I have tried this with gorm in many variations but none of them have worked. My most common issues were that gorm discarded my conditions and that it generated queries without a FROM
clause.
How can this query be performed using gorm?
I figured it out: InnerJoins()
does not seem to support many-to-many relations and preloading seems to be very broken (and also seems to happen after the fact, not "pre", which explains why the conditions don't apply). In addition to this, gorm seems to get confused when you try to use InnerJoins()
beyond a relational point where you have already used a different join function (it seems to paste SQL code in the wrong part of the query). The solution therefore is to query everything starting at the many-to-many relation via Joins()
and to just tell this function that you want an inner join:
Joins("INNER JOIN \"Bar_Foos\" ON \"Bar_Foos\".\"FooID\" = \"Foo\".\"ID\"").
Joins("INNER JOIN \"Bar\" ON \"Bar\".\"ID\" = \"Bar_Foos\".\"BarID\"").
Joins("INNER JOIN \"Project\" ON \"Project\".\"ID\" = \"Bar\".\"ProjectID\"").
Where("\"Project\".\"UserID\" = ?", user.UserID)