Представьте, что у нас есть следующие модели:
type Company struct {
gorm.Model
Name string
Addresses []Address
}
type Address struct {
gorm.Model
CompanyID uint64
Street string
City string
Country string
}
Я хочу взять все компании (и их адреса), которые имеют адрес в определенном месте. Что-то вроде этого:
SELECT company.*, address.* FROM company
INNER JOIN address ON address.company_id = company.id AND address.country = 'Bulgaria'
Так что если у компании нет адреса в конкретном месте, я его в итоге вообще не получу. Я пытался что-то вроде этого:
db.Joins("Addresses", "addresses.country = ?", "Bulgaria").Find(&companies)
Однако это не работает, потому что GORM не принимает второй аргумент Joins (при использовании предварительной загрузки соединения), поэтому я должен проверить сгенерированный запрос и сделать что-то вроде этого:
db.Where(`"Address".country = ?`, "Bulgaria").Joins("Addresses").Find(&companies)
Есть ли лучший способ/не хакерский способ? Имейте в виду, что весь приведенный выше код является имитацией реальной проблемы, я не хотел раскрывать исходные модели/запросы.
@Попай мой плохой, отредактировано
Вы можете использовать Preload
для загрузки Addresses
в объект Company
.
Исходя из описанных вами условий, когда вы не хотите загружать компании, которые не соответствуют вашему фильтру, вы должны использовать INNER JOIN
Два варианта:
Во-первых, если ваша таблица называется company
, ваш запрос должен выглядеть так:
db.Table("company").
Preload("Addresses").
Joins("INNER JOIN addresses a ON a.company_id = company.id").
Where("a.country = ?", "Bulgaria").
Find(&companies)
Во-вторых, если ваша таблица называется companies
, вам следует попробовать следующее:
db.Preload("Addresses").
Joins("INNER JOIN addresses a ON a.company_id = companies.id").
Where("a.country = ?", "Bulgaria").
Find(&companies)
Обратите внимание, что таблицу можно назвать company
, и вы можете использовать второй пример, если вы указали параметр SingularTable: true
NamingStrategy для gorm.Open
.
Если вы используете Gorm v2, вы выполняете операции CRUD для has-one и one-to-many через ассоциации:
var companies []Company
var addresses []Address
countries := []string{"Bulgaria"}
db.Model(&Address).Where("country IN (?)", countries).Find(&addresses)
// The key is using the previously fetched variable as the model for the association query
db.Model(&addresses).Association("CompanyID").Find(&companies)
Это также работает для отношений «многие ко многим».
При сравнении необработанных SQL-запросов Gorm VS (db.Raw(SQLquery)
) вы обычно видите падение производительности. С другой стороны, вам не придется иметь дело с дополнительной сложностью построения необработанных строк SQL в Go, что довольно приятно. Я лично использую в своих проектах комбинацию как необработанных, так и построенных на основе gorm запросов :)
Почему вы используете
LEFT JOIN
? Это даст вам все компании.