doumo6356 2017-07-15 15:00
浏览 143

带有gorm的外键和相关数据

I'm using golang and gorm to talk to a MySQL database.

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.

After a very long time and reading lots of documentatin, SO questions and code samples I tried to do the following:

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. However, it was not the correct metadata.

In my test I added two metadata records and one default:

enter image description here enter image description here

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.

Indeed, when I turned on the gorm logs I saw that it ran the query:

[2017-07-15 17:51:50] [276.74ms] SELECT * FROM global_defaults WHERE global_defaults.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).

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. Without explicitly specifying the foreign key names in the API, the related data would just not be read. 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? 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)?

  • 写回答

0条回答 默认 最新

    报告相同问题?

    悬赏问题

    • ¥15 uniapp uview http 如何实现统一的请求异常信息提示?
    • ¥15 有了解d3和topogram.js库的吗?有偿请教
    • ¥100 任意维数的K均值聚类
    • ¥15 stamps做sbas-insar,时序沉降图怎么画
    • ¥15 买了个传感器,根据商家发的代码和步骤使用但是代码报错了不会改,有没有人可以看看
    • ¥15 关于#Java#的问题,如何解决?
    • ¥15 加热介质是液体,换热器壳侧导热系数和总的导热系数怎么算
    • ¥100 嵌入式系统基于PIC16F882和热敏电阻的数字温度计
    • ¥20 BAPI_PR_CHANGE how to add account assignment information for service line
    • ¥500 火焰左右视图、视差(基于双目相机)