sql - Golang gorm - 在不使用预加载的情况下获取关系
问题描述
我是 gorm 和 golang 的新手,我正在处理一个查询,以获取用户与对话中用户的对话。我的查询按预期工作,但我的问题是它没有带来用户的关系。
这是我的对话模型:
type Conversation struct {
ID uint `gorm:"primarykey"`
Users []User `gorm:"many2many:user_has_conversations;"`
Messages []ConversationMessage
}
这是我对分贝的要求:
var conversations []model.Conversation
result := r.db.Debug().Scopes(
pagination.Paginate,
scope.OrderByIDDescTable(conversationsTable),
).Joins(
"INNER JOIN `user_has_conversations` ON `user_has_conversations`.`conversation_id` = `conversations`.`id`",
).Joins(
"INNER JOIN `users` ON `users`.`id` = `user_has_conversations`.`user_id` AND `users`.`id` = ?",
UserID,
).Find(&conversations)
此查询工作正常,并且正确地带来了用户的对话,但没有将关系中的用户归还给我,并且当您查看它运行的查询时,它不会带来用户字段。
执行的查询:
SELECT `conversations`.`id`
FROM `conversations`
INNER JOIN `user_has_conversations` ON `user_has_conversations`.`conversation_id` = `conversations`.`id`
INNER JOIN `users` ON `users`.`id` = `user_has_conversations`.`user_id` AND `users`.`id` = 1
ORDER BY `conversations`.`id` desc LIMIT 10;
在查询中您可以看到查询是正确的,但没有选择与关系的字段。
如果我在内部连接中也使用预加载确实给了我正确的解决方案,但我认为当我已经加入对用户进行预加载以再次获得用户时,这对性能没有好处。我希望能够通过加入来获得它,而不是使用预加载。
这个例子有效,但如果有办法,我想在没有预加载的情况下使用它。
result := r.db.Debug().Scopes(
pagination.Paginate,
scope.OrderByIDDescTable(conversationsTable),
).Preload("Users").Joins(
"INNER JOIN `user_has_conversations` ON `user_has_conversations`.`conversation_id` = `conversations`.`id`",
).Joins(
"INNER JOIN `users` ON `users`.`id` = `user_has_conversations`.`user_id` AND `users`.`id` = ?",
UserID,
).Find(&conversations)
解决方案
您可以通过为 gorm 实现自定义数据类型并在查询中使用它来接收users
来自数据库的切片(如下所示)来做到这一点。
自定义数据类型必须实现 Scanner 和 Valuer 接口,因此 GORM 知道如何将其接收/保存到数据库中。 https://gorm.io/docs/data_types.html
type Users []User
func (u Users) Value() (driver.Value, error) {
return json.Marshal(u)
}
func (u *Users) Scan(src interface{}) error {
if bytes, ok := src.([]byte); ok {
return json.Unmarshal(bytes, u)
}
return errors.New(fmt.Sprint("Failed to unmarshal JSON from DB", src))
}
所以你的conversation
类型应该更新如下:
type Conversation struct {
ID uint `gorm:"primarykey"`
Users Users `gorm:"-"`
Messages []ConversationMessage
}
为了能够在对话中查询所有参与的用户,我们需要使用jsonb_agg
和构建 json 对象jsonb_build_object
var conversations []model.Conversation
result := r.db.Debug().Scopes(
pagination.Paginate,
scope.OrderByIDDescTable(conversationsTable),
).
Select(conversationsTable + ".*," +
"jsonb_agg(
distinct jsonb_build_object(
'id', u.id,
'name', u.name,
//...
)
) as users").
Joins("INNER JOIN `user_has_conversations` ON `user_has_conversations`.`conversation_id` = `conversations`.`id`").
Joins("INNER JOIN `users` as u ON `u`.`id` = `user_has_conversations`.`user_id` AND `u`.`id` = ?", UserID).
Find(&conversations)
推荐阅读
- asp.net - dll 文件更改时重新加载 ASP.NET Core 应用程序(bin 部署)
- java - 来自 Java 类的 Spring Boot-set JmsTemplate 配置属性(不是来自应用程序属性文件)
- c++ - uWebSockets setUserData 线程安全吗?
- corda - $$Error:Counterparty 在未注册的消息类流的意外时间发送会话拒绝消息
- ios - 没有调用“hasBytesAvailable”
- javascript - Dialogflow api 调用有效,但聊天机器人关闭
- javascript - SyntaxError: Unexpected token { 尝试运行量角器测试时
- php - php 每个月的第一周数
- java - Android - 如何将一个扩展名的文件添加到列表视图
- kotlin - 为什么注释类不能推断类型参数?