如何将更新传播到相关表?

问题描述 投票:0回答:1

情况

假设我想在 CRUD-API 中读写更新两种对象:

type Player struct {
    ID              *uuid.UUID  `gorm:"type:uuid;primary_key;" json:"ID"`
    TeamID          *uuid.UUID  `gorm:"type:uuid" json:"UserID"`
    Name            string      `json:"Content"`
    gorm.Model
}

type Team struct {
    ID              *uuid.UUID  `gorm:"type:uuid;primary_key;" json:"ID"`
    Players         []Player    `gorm:"foreignKey:TeamID;references:ID" json:"Players"`
    Name            string      `json:"Content"`
    gorm.Model
}

gorm.Model
包含3个时间戳:
CreatedAt
UpdatedAt
DeletedAt
。当我更改
Player
的名称时,
UpdatedAt
时间戳也会更改。到目前为止,一切都很好。现在,我想做的是将相关
UpdatedAt
Team
时间戳设置为当前时间戳。 (为什么?看下面...)

我尝试了什么

GORM
(理论上)具有现成的强大功能:
BeforeSave()
BeforeUpdate()
AfterSave()
AfterUpdate()
... - 这些功能应该做我想要的,当我执行以下操作...

func (player *Player) BeforeUpdate(tx *gorm.DB) (err error) {
    if player.TeamID != nil && *player.TeamID != uuid.Nil {
        tx.Model(&Team{}).Where("id = ?", *player.TeamID).Update("updated_at", time.Now())
    }

    return
}

这应该是我想要的——但事实并非如此。也许有人可以帮忙。

BeforeUpdate()
对数据库没有任何影响。但是,该函数被调用 - 我检查过。另外,如果您认为原因是
UpdatedAt
gorm.Model
的一部分... - 事实并非如此。我尝试更改
Team
表中的其他字段。也没有用。

我觉得让这些功能发挥作用应该是最干净的方式,但如果你认为你有替代解决方案,那么我也对此非常开放。

最后一点 - 在这个玩具示例中,

Player
的更新应该更新
Team
,而不是更多。但在我的实际示例中,当时发生的
Team
更新应该会触发相关的另一次更新......假设
League
记录。此信息可能很重要。

背景

我想这样做的原因是为了跨设备同步数据。这个想法如下。如果我是该数据模型所属应用程序的用户,那么我可能上周同步了本地存储的数据。今天,我上线了,与此同时,一个

Player
更改了名字。当上述行为可能时,应用程序只需检查哪个
Team
已更新,而不是更新我拥有的所有团队的整个本地数据。

go go-gorm data-synchronization
1个回答
0
投票

你的想法是正确的。你只是用错了方法。

您应该使用AfterUpdate。检查这个例子:

package main

import (
    "fmt"
    "log"

    "github.com/google/uuid"
    "gorm.io/driver/sqlite"
    "gorm.io/gorm"
)

type Player struct {
    ID     *uuid.UUID `gorm:"type:uuid;primaryKey;" json:"ID"`
    TeamID *uuid.UUID `gorm:"type:uuid" json:"TeamID"`
    Name   string     `json:"Name"`
    gorm.Model
}

type Team struct {
    ID      *uuid.UUID `gorm:"type:uuid;primaryKey;" json:"ID"`
    Players []Player   `gorm:"foreignKey:TeamID;references:ID" json:"Players"`
    Name    string     `json:"Name"`
    gorm.Model
}

func (player *Player) AfterUpdate(tx *gorm.DB) (err error) {
    if player.TeamID != nil && *player.TeamID != uuid.Nil {
        tx.Model(&Team{}).Where("id = ?", *player.TeamID).Update("updated_at", player.UpdatedAt)
    }

    return
}

func main() {
    db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
    if err != nil {
        log.Fatalf("failed to connect database: %v", err)
    }

    if err := db.AutoMigrate(&Team{}, &Player{}); err != nil {
        log.Fatalf("failed to migrate database: %v", err)
    }

    teamID := uuid.New()
    team := Team{
        ID:   &teamID,
        Name: "Team A",
    }

    if err := db.Create(&team).Error; err != nil {
        log.Fatalf("failed to create team: %v", err)
    }

    playerID := uuid.New()
    player := Player{
        ID:     &playerID,
        TeamID: &teamID,
        Name:   "Player 1",
    }

    if err := db.Create(&player).Error; err != nil {
        log.Fatalf("failed to create player: %v", err)
    }

    fmt.Printf("Initial UpdatedAt - Team: %v, Player: %v\n", team.UpdatedAt, player.UpdatedAt)

    if err := db.Model(&player).Update("Name", "Updated Player 1").Error; err != nil {
        log.Fatalf("failed to update player: %v", err)
    }

    var updatedTeam Team
    if err := db.First(&updatedTeam, "id = ?", teamID).Error; err != nil {
        log.Fatalf("failed to retrieve team: %v", err)
    }

    var updatedPlayer Player
    if err := db.First(&updatedPlayer, "id = ?", playerID).Error; err != nil {
        log.Fatalf("failed to retrieve player: %v", err)
    }

    fmt.Printf("Updated UpdatedAt - Team: %v, Player: %v\n", updatedTeam.UpdatedAt, updatedPlayer.UpdatedAt)
}

跑步时:

go run main.go 
Initial UpdatedAt - Team: 2025-01-21 09:56:07.517172905 -0300 -03, Player: 2025-01-21 09:56:07.52014034 -0300 -03
Updated UpdatedAt - Team: 2025-01-21 09:56:07.521738862 -0300 -0300, Player: 2025-01-21 09:56:07.521738862 -0300 -0300
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.