Как (предварительно) присоединиться к таблице в пользовательском столбце?

Представьте, что у нас есть следующие модели:

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)

Есть ли лучший способ/не хакерский способ? Имейте в виду, что весь приведенный выше код является имитацией реальной проблемы, я не хотел раскрывать исходные модели/запросы.

Почему вы используете LEFT JOIN? Это даст вам все компании.

Popeye 10.12.2020 11:29

@Попай мой плохой, отредактировано

Asen Valchev 10.12.2020 11:40
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
2
2
1 218
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы можете использовать 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.

Ezequiel Muns 12.12.2020 16:48

Если вы используете 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 запросов :)

Другие вопросы по теме