当前位置: 首页 > 知识库问答 >
问题:

gorm为在数据库表中插入数据而执行的不必要查询

谢烨烨
2023-03-14

我正在尝试Go语言和gorm,以便在我当前的项目中创建一个新功能。

我在MySQL中有以下数据库结构。

UserMaster表位于层次结构的顶部,它的主键列被许多其他表引用,它们自己将其用作主列。UserLogin表就是这样的表之一。这不是完美的数据库设计,但这是我将要处理的数据库结构,并且不可能更改该结构。

以下是我为go中的UserMaster和UserLogin创建的模型类。

type UserMaster struct {
    UserId      string    `gorm:"column:UserId;PRIMARY_KEY";size:20`
    CreatedDate time.Time `gorm:"column:CreatedDate"`
    IsActive    bool      `gorm:"column:IsActive"`
    UserLogin   UserLogin `gorm:"foreignkey:Id"`
}

type UserLogin struct {
    Id            string    `gorm:"column:Id;PRIMARY_KEY";size:20"`
    UserName      string    `gorm:"column:UserName;unique"`
    EmailId       string    `gorm:"column:EmailId;unique"`
    PasswordHash  string    `gorm:"column:PasswordHash"`
    PasswordSalt  string    `gorm:"column:PasswordSalt"`
    LastLoginDate time.Time `gorm:"column:LastLoginDate"`
}

func (UserMaster) TableName() string {
    return "usermaster"
}

func (UserLogin) TableName() string {
    return "userlogin"
}

我希望通过gorm在UserMaster和UserLogin表中创建行,只需保存完全填充的UserMaster实例。

下面是我为此编写的代码。

func main() {
    db, err := gorm.Open("mysql", "user:password@tcp(localhost:3306)/ormsample")

    if err != nil {
        panic("Failed to connect the database.")
    }

    defer db.Close()

    createNewUser(db, "someuser009@yopmail.com", "j;dfasdasdf")
}

func createNewUser(db *gorm.DB, emailId string, password string) UserMaster {
    userId := createUserId()

    newUser := &UserMaster{}
    newUser.UserId = userId
    newUser.CreatedDate = time.Now()
    newUser.UserLogin = UserLogin{}
    newUser.UserLogin.UserName = emailId
    newUser.UserLogin.EmailId = emailId
    newUser.UserLogin.PasswordHash = password
    newUser.UserLogin.PasswordSalt = "SomeSalt"

    db.Debug().Model(&newUser).Create(&newUser)

    return *newUser
}

func createUserId() string {
    uuidWithHyphen := uuid.New()
    uuid := strings.Replace(uuidWithHyphen.String(), "-", "", -1)

    return strings.ToUpper(uuid[:12])
}

这整件事的工作正如预期的那样,这意味着它正在向UserMaster和UserLogin表插入记录。

问题在于gorm执行此数据库操作的方式。以下是终端记录的SQL查询(因为我正在gorm db对象上使用Debug()函数)。

INSERT INTO `usermaster` (`UserId`,`CreatedDate`,`IsActive`) 
    VALUES ('1601F7E41E29','2020-03-22 22:24:08',false) 

UPDATE `userlogin` SET `UserName` = 'someuser009@yopmail.com', 
  `EmailId` = 'someuser009@yopmail.com', `PasswordHash` = 'j;dfasdasdf', 
  `PasswordSalt` = 'SomeSalt', `LastLoginDate` = '0000-00-00 00:00:00'  
  WHERE `userlogin`.`Id` = '1601F7E41E29'

SELECT * FROM `userlogin`  WHERE `userlogin`.`Id` = '1601F7E41E29' 
 ORDER BY `userlogin`.`Id` ASC LIMIT 1

INSERT INTO `userlogin` (`Id`,`UserName`,`EmailId`,`PasswordHash`,`PasswordSalt`,`LastLoginDate`)
VALUES ('1601F7E41E29','someuser009@yopmail.com','someuser009@yopmail.com',
 'j;dfasdasdf','SomeSalt','0000-00-00 00:00:00')

正如您注意到的,gorm执行2个INSERT、1个UPDATE和1个SELECT查询以插入到两个表中,而它应该只执行2个INSERT查询。

我在Go语言和gorm的各种论坛上搜索了很多关于这个的东西,但是没有找到任何可以解释这种行为的东西。

我们将非常感谢为解决此问题提供的任何帮助/指导/指导。

共有1个答案

万俟渊
2023-03-14

创建之前Gorm调用此函数

func beforeCreateCallback(scope *Scope) {
    if !scope.HasError() {
        scope.CallMethod("BeforeSave")
    }
    if !scope.HasError() {
        scope.CallMethod("BeforeCreate")
    }
}

这里,如果已经设置了主键,则gorm尝试使用给定的主键更新现有数据。这就是执行额外查询的原因。要解决此问题,请将UserId用作foreignkey用于UserLogin,这是UserLogin模型的主键,以便gorm尝试先保存子项,然后保存父项。不设置主键,使用BeforeCreate钩子设置

func (user *UserLogin) BeforeCreate(scope *gorm.Scope) error {
  scope.SetColumn("Id", ), createUserId())
  return nil
}

模型如:

type UserMaster struct {
    UserId      uint      `gorm:"column:UserId;PRIMARY_KEY;size:20"`
    CreatedDate time.Time `gorm:"column:CreatedDate"`
    IsActive    bool      `gorm:"column:IsActive"`
    UserLogin   UserLogin `gorm:"foreignkey:UserId"`
}

type UserLogin struct {
    Id            uint      `gorm:"column:Id;PRIMARY_KEY;size:20"`
    UserName      string    `gorm:"column:UserName;"`
    EmailId       string    `gorm:"column:EmailId;"`
    PasswordHash  string    `gorm:"column:PasswordHash"`
    PasswordSalt  string    `gorm:"column:PasswordSalt"`
    LastLoginDate time.Time `gorm:"column:LastLoginDate"`
}

同时使用模型(

db.Debug().Create(&newUser)

Gorm自动选择型号UserMasterfromnewUser

 类似资料:
  • 我试图使用下面的MySQL语句

  • 我有这样的查询(select id,reffid,someData from myTable): 我需要查询来执行以下操作:如果我有少于 4 个具有相同值的 reffid,则添加具有相同 reffid 的行并在 someData 中添加 -。结果查询应如下所示: 如何做到这一点?

  • 我想我在这段代码中遇到了一点问题:当我试图在数据库中插入值时,我遇到了一个错误。

  • 我有一个通过express连接的SQLite数据库,并且有使用express路由连接前端和后端的控制器。 表数据库 Knex插入行 反应前端 这里的问题是在前端,当我使用时,我得到的值为null,但当我用“text”替换stock.symbol,我得到的值为text。我在这里做错了什么?谢谢! 附注-这是常量存货

  • 我是android新手,这是我第一次在应用程序中使用room。未执行插入操作或未创建数据库或任何其他错误。 我不知道我做错了什么,所以我需要你的帮助。 此程序正在运行,但未显示任何结果。屏幕上什么都没有显示。 这是我的代码-请让我知道此代码中的错误以及我应该如何更正它。 汽车细节。JAVA 卡多。爪哇- CarListDatabase。JAVA CarRepository.java 公共无效get

  • 我有一个电子邮件订阅我的网站,我想插入到我的Wordpress数据库,所以我可以导出电子邮件列表。我已经创建了表wp_email_subscription,其中包含4个字段ID、名称、电子邮件和创建日期。对此将进行什么查询?有没有wordpress数据库脚本可以使用?