简体   繁体   English

gorm 的外键和相关数据

[英]Foreign keys and related data with gorm

I'm using golang and gorm to talk to a MySQL database.我正在使用 golang 和 gorm 与 MySQL 数据库对话。

I have a table with release metadata:我有一个包含发布元数据的表:

type OSType string
const (
    Windows OSType = "windows"
    Mac     OSType = "mac"
)

type AgentMetadata struct {
    Version         string              `gorm:"primary_key"`
    OS              OSType              `gorm:"primary_key" sql:"type:ENUM('windows','mac')"`
    Name            string              `sql:"not null"`
    Description     string              `sql:"not null"`
    ReleaseNotesUrl string              `sql:"not null"`

    UpdateTime      time.Time           `sql:"DEFAULT:current_timestamp"`
}

The releases are identified by a composite key - the OS and Version (number).版本由复合键标识 - 操作系统和版本(数字)。

I have another table which defines the default version that clients should download (by OS):我有另一个表定义了客户端应该下载的默认版本(按操作系统):

type GlobalDefault struct {
    OS              OSType          `gorm:"primary_key" sql:"type:ENUM('windows','mac')"`
    Version         string
    AgentMetadata   AgentMetadata   

    UpdateTime      time.Time       `sql:"DEFAULT:current_timestamp"`
}

What I want is to define two foreign keys from GlobalDefault to AgentMetadata (the pair OS and Version) and I want to be able to query the GlobalDefault table by its key OS and to get back a data structure which already contains the full AgentMetadata.我想要的是定义从 GlobalDefault 到 AgentMetadata 的两个外键(操作系统和版本对),我希望能够通过其关键操作系统查询 GlobalDefault 表并取回已经包含完整 AgentMetadata 的数据结构。

After a very long time and reading lots of documentatin, SO questions and code samples I tried to do the following:经过很长时间并阅读了大量文档、SO 问题和代码示例后,我尝试执行以下操作:

func (repository *AgentRepository)GetGlobalDefault(os OSType) (error, AgentMetadata) {
    gd := GlobalDefault{ OS:os }

    result := AgentMetadata{}
    return repository.connection.Find(&gd).Related(&result, "OS", "Version").Error, result
}

This "worked" in the sense that it really got the result filled up with AgentMetadata.从某种意义上说,这是“有效的”,因为它确实使结果充满了 AgentMetadata。 However, it was not the correct metadata.但是,它不是正确的元数据。

In my test I added two metadata records and one default:在我的测试中,我添加了两条元数据记录和一条默认值:

在此处输入图像描述 在此处输入图像描述

And when I called err, queryResult:= ar.GetGlobalDefault(defaultAgent.OS) instead of getting the 1.2.3 version metadata, I got the 1.2.3.1 metadata.当我调用err, queryResult:= ar.GetGlobalDefault(defaultAgent.OS)而不是获取 1.2.3 版本元数据时,我获取了 1.2.3.1 元数据。

Indeed, when I turned on the gorm logs I saw that it ran the query:事实上,当我打开 gorm 日志时,我看到它运行了查询:

[2017-07-15 17:51:50] [276.74ms] SELECT * FROM global_defaults WHERE global_defaults . [2017-07-15 17:51:50] [276.74ms] SELECT * FROM global_defaults WHERE global_defaults os = 'windows' os = '窗口'

[2017-07-15 17:51:50] [276.55ms] SELECT * FROM agent_metadata WHERE ( os = 'windows') [2017-07-15 17:51:50] [276.55ms] SELECT * FROM agent_metadata WHERE ( os = 'windows')

First, it ignored the fact that I have a composite key in the agent_metadata table, and second, instead of doing a single query with a join, it made two queries (which is really a waste of time).首先,它忽略了我在 agent_metadata 表中有一个复合键的事实,其次,它没有使用连接进行单个查询,而是进行了两次查询(这确实是在浪费时间)。

Another thing that bothers me is that I had to explicitly specify the foreign key names, whereas according to the documentation it seems that specifiying them is not needed or at least can be achieved by adding a tag:另一件困扰我的事情是我必须明确指定外键名称,而根据文档,似乎不需要指定它们,或者至少可以通过添加标签来实现:

type GlobalDefault struct {
    OS              OSType          `gorm:"primary_key" sql:"type:ENUM('windows','mac')"`
    Version         string
    AgentMetadata   AgentMetadata   `gorm:"ForeignKey:OS;AssociationForeignKey:OS"`

    UpdateTime      time.Time       `sql:"DEFAULT:current_timestamp"`
}

Here I only added a tag for the OS column, however, I tried concatenating the foreign key names and neither option seemed to have an effect on the result.在这里,我只为 OS 列添加了一个标签,但是,我尝试连接外键名称,这两个选项似乎都对结果没有影响。 Without explicitly specifying the foreign key names in the API, the related data would just not be read.如果不在 API 中明确指定外键名称,则不会读取相关数据。 Having the pass the names to the query means that my DB mapping is not consolidated in a single place and I don't like that.将名称传递给查询意味着我的数据库映射没有合并到一个地方,我不喜欢这样。

Can my scenario be solved?我的场景可以解决吗? Can I have a composite foreign key?我可以有一个复合外键吗? Can I specify all ORM properties in a single place?我可以在一个地方指定所有 ORM 属性吗? How can I make gorm create foreign keys in the DB (I noticed that the schema is created without foreign keys from GlobalDefault to AgentMetadata)?我怎样才能让 gorm 在数据库中创建外键(我注意到模式是在没有从 GlobalDefault 到 AgentMetadata 的外键的情况下创建的)?

How can I make gorm create foreign keys in the DB?如何让 gorm 在数据库中创建外键?

here is a sample:这是一个示例:

db.AutoMigrate(&model.User{}).
        AddForeignKey("account_id", "accounts(id)", "CASCADE", "CASCADE").
        AddForeignKey("role_id", "roles(id)", "RESTRICT", "RESTRICT")

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM