GORM GEN的CRUD

2023年 10月 30日 29.8k 0

上一篇:GROM GEN的代码生成

下一篇:GORM GEN的最佳实践

推荐有时间的同学可以将系列文章都过一遍有个印象、没有时间的同学可以通过关键词搜索找到自己需要的内容。

image.png

前面详细介绍代码生成的能力,包括直接同步数据库表生成、基于已有的model生成以及通过建表SQL生成三部分。本文将介绍如使用GEN生成的代码执行CRUD操作。

创建/插入

示例代码:github.com/go-gorm/gen…

1.1 初始化

这里可以看下前一篇代码生成,GEN推荐大家配置WithDefaultQuery模式,这样会生成全局单例变量,初始化一次其他地方可以直接使用。初始化建议调用一次,通常是直接写在init里面。

DefaultQuery模式生成的代码示例:

var (
   Q    = new(Query)
   Role *role
   User *user
)

func SetDefault(db *gorm.DB, opts ...gen.DOOption) {
   *Q = *Use(db, opts...)
   Role = &Q.Role
   User = &Q.User
}

新建一个init.go,调用初始化逻辑SetDefault


func init() {
   mysql.Init()
   SetDefault(mysql.DB(context.Background()))
}

1.2【批量】创建

主要包括创建/选择或者忽略字段的创建/批量的创建用法

package handler

import (
   "context"

   "github.com/go-gorm/gendemo/biz/dal/model"
   "github.com/go-gorm/gendemo/biz/dal/query"
   "github.com/go-gorm/gendemo/logs"
   "gorm.io/gorm/clause"
)

// SimpleCreate 简单的创建
func SimpleCreate(ctx context.Context) {
   vd := query.User
   user := &model.User{Name: "1", Phone: "12xxx"}
   //简单创建
   err := vd.WithContext(ctx).Create(user)
   if err != nil {
      logs.CtxError(ctx, "[SimpleCreate] Create err=%s", err.Error())
      return
   }
}

// SelectCreate 选择字段创建
func SelectCreate(ctx context.Context) {
   vd := query.User
   user := &model.User{Name: "1", Phone: "12xxx"}
   //创建语句只会写shop_id 字段
   err := vd.WithContext(ctx).Select(vd.Name).Create(user)
   if err != nil {
      logs.CtxError(ctx, "[SelectCreate] Create err=%s", err.Error())
      return
   }
}

// IgnoreCreate 忽略字段创建
func IgnoreCreate(ctx context.Context) {
   vd := query.User
   user := &model.User{Name: "1", Phone: "12xxx"}
   //创建语句忽略shop_id 字段
   err := vd.WithContext(ctx).Omit(vd.Name).Create(user)
   if err != nil {
      logs.CtxError(ctx, "[IgnoreCreate] Create err=%s", err.Error())
      return
   }
}

// BatchCreate 批量创建
func BatchCreate(ctx context.Context) {
   vd := query.User
   users := []*model.User{
      {Name: "1", Phone: "11xxx"},
      {Name: "2", Phone: "12xxx"},
      {Name: "3", Phone: "13xxx"},
   }
   //批量创建
   err := vd.WithContext(ctx).Create(users...)
   if err != nil {
      logs.CtxError(ctx, "[BatchCreate] Create err=%s", err.Error())
      return
   }
   //批量创建,设置批量创建数量2,即一次创建两条
   err = vd.WithContext(ctx).CreateInBatches(users, 2)
   if err != nil {
      logs.CtxError(ctx, "[BatchCreate] Create err=%s", err.Error())
      return
   }
}

1.3 创建更新(upsert)

主要介绍如何处理,创建冲突的情况(主键和唯一键冲突);包括全量更新/部分更新以及忽略不更新

// Upsert 更新创建
func Upsert(ctx context.Context) {
   vd := query.User
   users := []*model.User{
      {Name: "1", Phone: "11xxx"},
      {Name: "2", Phone: "12xxx"},
      {Name: "3", Phone: "13xxx"},
   }
   //创建时冲突直接忽略
   err := vd.WithContext(ctx).Clauses(clause.OnConflict{DoNothing: true}).Create(users...)
   if err != nil {
      logs.CtxError(ctx, "[Upsert] Create err=%s", err.Error())
      return
   }
   //创建时冲突,更新所有字段
   err = vd.WithContext(ctx).Clauses(clause.OnConflict{UpdateAll: true}).Create(users...)
   if err != nil {
      logs.CtxError(ctx, "[Upsert] Create err=%s", err.Error())
      return
   }
   //创建时冲突,更新指定字段
   err = vd.WithContext(ctx).Clauses(clause.OnConflict{
      DoUpdates: clause.Assignments(map[string]interface{}{"shop_id": "group_id"}),
   }).Create(users...)
   if err != nil {
      logs.CtxError(ctx, "[Upsert] Create err=%s", err.Error())
      return
   }
}

更新

示例代码:github.com/go-gorm/gen…

2.1 简单更新

这部分主要介绍,如何更新单个字段,如何选择要更新的字段,以及如何更新struct的零值字段等

package handler

import (
   "context"

   "github.com/go-gorm/gendemo/biz/dal/model"
   "github.com/go-gorm/gendemo/biz/dal/query"
   "github.com/go-gorm/gendemo/logs"
)

// SimpleUpdate 简单的更新
func SimpleUpdate(ctx context.Context) {
   vd := query.User
   //只更新单个字段
   update, err := vd.WithContext(ctx).Where(vd.ID.Eq(1)).Update(vd.Name, "1")
   if err != nil {
      logs.CtxError(ctx, "[SimpleUpdate] Update err=%s", err.Error())
      return
   }
   if update.RowsAffected <= 0 {
      logs.CtxWarn(ctx, "[SimpleUpdate] Update RowsAffected=0")
   }
   //更新有限多字段
   update, err = vd.WithContext(ctx).Where(vd.ID.Eq(1)).
      UpdateSimple(vd.Name.Value("2"), vd.Extra.Zero())
   if err != nil {
      logs.CtxError(ctx, "[SimpleUpdate] Update err=%s", err.Error())
      return
   }
   if update.RowsAffected <= 0 {
      logs.CtxWarn(ctx, "[SimpleUpdate] Update RowsAffected=0")
   }

   //通过struct更新,默认是会忽略零值,也就是这里只会更新 shop_id和group_id
   user := &model.User{Name: "1", Phone: "12xxx"}
   update, err = vd.WithContext(ctx).Where(vd.ID.Eq(1)).
      Updates(user)
   if err != nil {
      logs.CtxError(ctx, "[SimpleUpdate] Update err=%s", err.Error())
      return
   }
   if update.RowsAffected <= 0 {
      logs.CtxWarn(ctx, "[SimpleUpdate] Update RowsAffected=0")
   }

   //通过struct更新,还想更新非零值,可以加sleet
   update, err = vd.WithContext(ctx).Where(vd.ID.Eq(1)).
      Select(vd.Name,vd.Extra).Updates(user)
   //或者直接更新所有,select *
   update, err = vd.WithContext(ctx).Where(vd.ID.Eq(1)).
      Select(vd.ALL).Updates(user)
   if err != nil {
      logs.CtxError(ctx, "[SimpleUpdate] Update err=%s", err.Error())
      return
   }
   if update.RowsAffected <= 0 {
      logs.CtxWarn(ctx, "[SimpleUpdate] Update RowsAffected=0")
   }

   //当然除了上面的方式,也可以用map,会更新map里的所有字段
   update, err = vd.WithContext(ctx).Where(vd.ID.Eq(1)).
      Updates(map[string]interface{}{"name": "3", "phone": 3})
   if err != nil {
      logs.CtxError(ctx, "[SimpleUpdate] Update err=%s", err.Error())
      return
   }
   if update.RowsAffected <= 0 {
      logs.CtxWarn(ctx, "[SimpleUpdate] Update RowsAffected=0")
   }
}

2.2 基于查询更新

主要适用于,本次更新的字段的值 来源于另一个查询的结果

// UpdateFromQuery 查询更新
//!!!这里只是举例如何根据查询更新,没有任何业务意义甚至看起来更新很不合理
func UpdateFromQuery(ctx context.Context) {
   vd := query.User
   co := query.Role
   update, err := vd.WithContext(ctx).Debug().Where(vd.ID.Eq(1)).
      Update(vd.Name, co.WithContext(ctx).Select(co.Name).Where(co.ID.Eq(3)))
   //UPDATE `user` SET `name`=(SELECT `role`.`name` FROM `role` WHERE `role`.`id` = 3)
   //WHERE `user`.`id` = 1
   if err != nil {
      logs.CtxError(ctx, "[UpdateFromQuery] Update err=%s", err.Error())
      return
   }
   if update.RowsAffected <= 0 {
      logs.CtxWarn(ctx, "[UpdateFromQuery] Update RowsAffected=0")
   }

   //多个字段更新
   vdt := vd.As("vdt")
   ua := vd.As("ua")
   update, err = ua.WithContext(ctx).Debug().
      UpdateFrom(vdt.WithContext(ctx).Select(vd.Name, vd.Phone).Where(vd.ID.Eq(1))).
      Where(ua.ID.Eq(2)).UpdateSimple(
      ua.Name.SetCol(vdt.Name), ua.Phone.SetCol(vdt.Phone))
   //UPDATE `user` AS `ua`,
   //(SELECT `user`.`name`,`user`.`phone` FROM `user` WHERE `user`.`id` = 1) AS `vdt`
   //SET `ua`.`name`=`vdt`.`name`,`ua`.`phone`=`vdt`.`phone` WHERE `ua`.`id` = 2
   if err != nil {
      logs.CtxError(ctx, "[UpdateFromQuery] Update err=%s", err.Error())
      return
   }
   if update.RowsAffected <= 0 {
      logs.CtxWarn(ctx, "[UpdateFromQuery] Update RowsAffected=0")
   }

}

删除

示例代码:github.com/go-gorm/gen…

删除这里没有太多的逻辑,一般就是带上条件直接执行删除就行;可能唯一想要关注的就是软删除。

package handler

import (
   "context"

   "github.com/go-gorm/gendemo/biz/dal/query"
   "github.com/go-gorm/gendemo/logs"
)

// SimpleDelete 简单的删除
func SimpleDelete(ctx context.Context) {
   vd := query.User
   //指定条件
   result, err := vd.WithContext(ctx).Where(vd.Name.Eq("1")).Delete()
   if err != nil {
      logs.CtxError(ctx, "[SimpleDelete] Delete err=%s", err.Error())
      return
   }
   if result.RowsAffected == 0 {
      //no deleted record
   }

   //如果你的结构里有软删除字段,默认逻辑都是走软删除
   //具体的可以参考 https://gorm.io/docs/delete.html#Find-soft-deleted-records
   //软删除的情况下,也是可以实现物理删除的,加上 Unscoped()
   result, err = vd.WithContext(ctx).Where(vd.Name.Eq("1")).Unscoped().Delete()
   if err != nil {
      logs.CtxError(ctx, "[SimpleDelete] Delete err=%s", err.Error())
      return
   }
}

事务

示例代码:
github.com/go-gorm/gen…

事务推荐使用Transaction方法自动管理事务的开始和提交/回滚;当然也支持手动管理事务,切记手动开事务之后一定要判断err;同时开完事务一定要记得提交或者回滚。

package handler

import (
   "context"

   "github.com/go-gorm/gendemo/biz/dal/model"
   "github.com/go-gorm/gendemo/biz/dal/query"
   "github.com/go-gorm/gendemo/logs"
)

// AutoTransAction 自动事务
func AutoTransAction(ctx context.Context) {
   //通过Transaction,开事务,只要返回err就会自动回滚,没有err就会自动提交
   err := query.Q.Transaction(func(tx *query.Query) error {
      //事务里要用事务的query操作(tx)
      err := tx.Role.WithContext(ctx).Create(&model.Role{Name: "test"})
      if err != nil { //有err返回
         return err
      }
      err = tx.User.WithContext(ctx).Create(&model.User{Name: "1"})
      if err != nil { //有err返回自动回滚
         return err
      }
      return err
   })
   if err != nil {
      logs.CtxError(ctx, "[AutoTransAction] Transaction err=%s", err.Error())
   }

   //事务也支持嵌套
   err = query.Q.Transaction(func(tx *query.Query) error {
      //事务里要用事务的query操作(tx)
      cerr := tx.Role.WithContext(ctx).Create(&model.Role{Name: "test"})
      if cerr != nil { //有err返回
         return cerr
      }
      tx.Transaction(func(tx2 *query.Query) error {
         uerr := tx2.User.WithContext(ctx).Create(&model.User{Name: "1"})
         if uerr != nil { //有err返回自动回滚
            return uerr
         }
         return tx2.User.WithContext(ctx).Create(&model.User{Name: "2"})
      })

      return err
   })
   if err != nil {
      logs.CtxError(ctx, "[AutoTransAction] Transaction err=%s", err.Error())
   }
}

// ManualTransAction 手动事务
func ManualTransAction(ctx context.Context) {
   //开启事务
   tx := query.Q.Begin()
   //记得判断err
   if tx.Error != nil {
      //事务开失败了
      return
   }
   var err error
   defer func() {
      if recover() != nil || err != nil {
         //回滚事务
         _ = tx.Rollback()
      }
   }()

   err = tx.Role.WithContext(ctx).Create(&model.Role{Name: "test"})
   if err != nil {
      return
   }
   //提交事务
   err = tx.Commit()

}

查询

示例:
github.com/go-gorm/gen…

5.1 字段类型和操作

查询部分主要是构建查询条件,所以这里先列举下每种dao字段类型拥有的操作。

  • 通用字段类型(Field):IsNull/IsNotNull/Count/Eq/Neq/Gt/Gte/Lt/Lte/Like/Value/Sum/IfNull
  • id := field.NewField("user", "id")
    anotherID := field.NewField("another", "id")
    // `user`.`id` = `another`.`id`
    id.EqCol(anotherID)
    // user`.`id` IS NULL
    id.IsNull()
    
  • 整形(Int/UInt):Eq/Neq/Gt/Gte/Lt/Lte/In/NotIn/Between/NotBetween/Like/NotLike/Add/Sub/Mul/Div/Mod/FloorDiv/RightShift/LeftShift/BitXor/BitAnd/BitOr/BitFlip/Value/Zero/Sum/IfNull
  • // int field
    f := field.NewInt("user", "id")
    // `user`.`id` = 123
    f.Eq(123)
    // `user`.`id` DESC
    f.Desc()
    // `user`.`id` AS `user_id`
    f.As("user_id")
    // COUNT(`user`.`id`)
    f.Count()
    // SUM(`user`.`id`)
    f.Sum()
    // SUM(`user`.`id`) > 123
    f.Sum().Gt(123)
    // ((`user`.`id`+1)*2)/3
    f.Add(1).Mul(2).Div(3),
    // `user`.`id` <<< 3
    f.LeftShift(3)
    
  • 浮点型(Float):Eq/Neq/Gt/Gte/Lt/Lte/In/NotIn/Between/NotBetween/Like/NotLike/Add/Sub/Mul/Div/FloorDiv/Floor/Value/Zero/Sum/IfNull

  • 字符串(String):Eq/Neq/Gt/Gte/Lt/Lte/Between/NotBetween/In/NotIn/Like/NotLike/Regexp/NotRegxp/FindInSet/FindInSetWith/Value/Zero/IfNull

  • name := field.NewString("user", "name")
    // `user`.`name` = "modi"
    name.Eq("modi")
    // `user`.`name` LIKE %modi%
    name.Like("%modi%")
    // `user`.`name` REGEXP .*
    name.Regexp(".*")
    // `user`.`name` FIND_IN_SET(`name`,"modi,jinzhu,zhangqiang")
    name.FindInSet("modi,jinzhu,zhangqiang")
    // `uesr`.`name` CONCAT("[",name,"]")
    name.Concat("[", "]")
    
  • 布尔型(Bool):Not/Is/And/Or/Xor/BitXor/BitAnd/BitOr/Value/Zero
  • active := field.NewBool("user", "active")
    // `user`.`active` = TRUE
    active.Is(true)
    // NOT `user`.`active`
    active.Not()
    // `user`.`active` AND TRUE
    active.And(true)
    
  • 时间类型(Time):Eq/Neq/Gt/Gte/Lt/Lte/Between/NotBetween/In/NotIn/Add/Sub/Date/DateDiff/DateFormat/Now/CurDate/CurTime/DayName/MonthName/Month/Day/Hour/Minute/Second/MicroSecond/DayOfWeek/DayOfMonth/FromDays/FromUnixtime/Value/Zero/Sum/IfNull
  • birth := field.NewString("user", "birth")
    // `user`.`birth` = ? (now)
    birth.Eq(time.Now())
    // DATE_ADD(`user`.`birth`, INTERVAL ? MICROSECOND)
    birth.Add(time.Duration(time.Hour).Microseconds())
    // DATE_FORMAT(`user`.`birth`, "%W %M %Y")
    birth.DateFormat("%W %M %Y")
    

    5.2 单值查询

    GORM Gen 提供了三个查询单值的方法,First/Take/Last,默认都会加上limit 1的限制,同时在没有查到的时候会返回ErrRecordNotFound错误;其中First还会加上主键排序,Last会加上主键倒排。

    如果就不希望返回这个找不到的错误,可以选择手动加Limit(1),然后用Find/Scan查询。

    // SingleValueQuery 单值查询
    func SingleValueQuery(ctx context.Context) {
       u := query.User
    
       // 查用户1的第一条
       user, err := u.WithContext(ctx).Where(u.ID.Eq(1)).First()
       // SELECT * FROM user  WHERE `user`.`id` = 1 ORDER BY id LIMIT 1;
       if err != nil {
          logs.CtxError(ctx, "[SingleValueQuery] First err=%s", err.Error())
       }
       fmt.Println(user)
    
       // 查一条,走数据库的默认排序
       user, err = u.WithContext(ctx).Take()
       // SELECT * FROM users LIMIT 1;
       if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
          logs.CtxError(ctx, "[SingleValueQuery] Take err=%s", err.Error())
       }
       fmt.Println(user)
    
       // 查用户1的最后一条
       user, err = u.WithContext(ctx).Where(u.ID.Eq(1)).Last()
       // SELECT * FROM user  WHERE `user`.`id` = 1 ORDER BY id DESC LIMIT 1;
       if err != nil {
          logs.CtxError(ctx, "[SingleValueQuery] Last err=%s", err.Error())
       }
       fmt.Println(user)
    
       // 走主库查询
       user, err = u.WithContext(ctx).WriteDB().Last()
    
       // check error ErrRecordNotFound
       errors.Is(err, gorm.ErrRecordNotFound)
    
       //如果不希望返回err,可以用limit+find/scan
       users, err := u.WithContext(ctx).Where(u.ID.Eq(1)).Limit(1).Find()
       if len(users) > 0 {
          fmt.Println(users[0])
       }
    
       var User *model.User
       err = u.WithContext(ctx).Where(u.ID.Eq(1)).Limit(1).Scan(&User)
       fmt.Println(User)
    }
    

    5.3 简单查询

    这部分主要是一些简单的查询使用,比如分页,统计、分组、JSON查询

    // SimpleQuery 简单查询
    func SimpleQuery(ctx context.Context) {
       u := query.User
    
       //单条件,用户1的数据
       users, err := u.WithContext(ctx).Where(u.ID.Eq(1)).Limit(10).Find()
       if err != nil {
          logs.CtxError(ctx, "[SimpleQuery] Find err=%s", err.Error())
       }
       fmt.Println(users)
    
       //统计
       total, err := u.WithContext(ctx).Where(u.ID.Eq(1)).Count()
       if err != nil {
          logs.CtxError(ctx, "[SimpleQuery] Count err=%s", err.Error())
       }
       fmt.Println(total)
    
       //分页查询,排序
       users, total, err = u.WithContext(ctx).Where(u.ID.Eq(1)).Order(u.ID.Desc(), u.Phone).FindByPage(0, 10)
       if err != nil {
          logs.CtxError(ctx, "[SimpleQuery] Count err=%s", err.Error())
       }
       fmt.Println(total)
       fmt.Println(users)
    
       //多条件AND查询 用户1
       users, total, err = u.WithContext(ctx).Where(u.Name.Eq("1")).FindByPage(0, 10)
    
       //OR条件查询
       // (`user`.`id` = 1 AND `user`.`name` = 1) OR (`user`.`id` = 2)
       users, total, err = u.WithContext(ctx).Where(u.ID.Eq(1), u.Name.Eq("1")).Or(u.ID.Eq(2)).FindByPage(0, 10)
    
       // 元组查询,多个字段的条件组合
       //查询用户1类型 以及用户2类型2的
       users, err = u.WithContext(ctx).Where(u.Columns(u.Name, u.Phone).In(field.Values([][]interface{}{{"1", "1"}, {"2", "2"}}))).Find()
       // SELECT * FROM `user` WHERE (`user.name`, `user.phone`) IN ((1,1),(2,2);
    
       //JSON查询
       users, err = u.WithContext(ctx).Where(gen.Cond(datatypes.JSONQuery("extra").HasKey("xx_id"))...).Find()
       // SELECT * FROM `user` WHERE JSON_EXTRACT(`attributes`,'$.user_id') IS NOT NULL;
    
       //选择查询的字段
       users, err = u.WithContext(ctx).Select(u.ID, u.Name).Where(u.ID.Eq(1)).Find()
       //去重
       users, err = u.WithContext(ctx).Distinct(u.ID, u.Phone).Order(u.ID, u.Name.Desc()).Find()
    
       //分组
       var Tuser []struct {
          Name  string
          Total int
       }
       err = u.WithContext(ctx).Select(u.ID, u.ID.Count().As("total")).Group(u.ID).Scan(&Tuser)
       //加上Having
       err = u.WithContext(ctx).Select(u.ID, u.ID.Count().As("total")).Group(u.ID).Having(u.Name.Eq("10")).Scan(&Tuser)
    
    }
    

    5.4 复杂查询

    复杂查询将会介绍,JOIN连表、子查询、查询创建等使用方式

    // ComplexQuery 复杂查询
    func ComplexQuery(ctx context.Context) {
       u := query.User
       c := query.Role
       //连表查询(示例没有业务含义)
       type Result struct {
          RoleName string
          Phone    string
          ID       int64
       }
    
       var result Result
       //和其他表连接
       err := u.WithContext(ctx).Select(u.ID, u.Phone, c.Name.As("role_name")).LeftJoin(c, c.ID.EqCol(u.RoleID)).Scan(&result)
       // SELECT `user`.`phone`,`role`.`name` as role_name FROM `user` left join `role` on `role`.`id` = `user`.`role_id`
       if err != nil {
          logs.CtxError(ctx, "[ComplexQuery] LeftJoin Scan err=%s", err.Error())
       }
       fmt.Println(result)
    
       // 同一个表做连接
       var result2 Result
       u2 := u.As("u2")
       err = u.WithContext(ctx).Select(u.ID, u2.Phone).LeftJoin(u2, u2.ID.EqCol(u.ID)).Scan(&result2)
       // SELECT users.id, u2.phone FROM `user` left join `user` u2 on u2.id = user.id
    
       //子查询的连接
       var result3 Result
       c2 := c.As("c2")
       err = u.WithContext(ctx).Select(u.ID, c2.Name).LeftJoin(c.WithContext(ctx).Select(c.ID, c.Name).Where(c.ID.Gt(100)).As("c2"), c2.ID.EqCol(u.RoleID)).Scan(&result3)
       // SELECT `user`.`id`,c2.`name` FROM `user` left join (select id,name from role  where id > 100) as c2 on c2.id = `user`.`role_id`
    
    }
    
    //子查询
    o := query.Order
    u := query.User
    
    orders, err := o.WithContext(ctx).Where(o.WithContext(ctx).Columns(o.Amount).Gt(o.WithContext(ctx).Select(o.Amount.Avg())).Find()
    // SELECT * FROM "orders" WHERE amount > (SELECT AVG(amount) FROM "orders");
    
    subQuery := u.WithContext(ctx).Select(u.Age.Avg()).Where(u.Name.Like("name%"))
    users, err := u.WithContext(ctx).Select(u.Age.Avg().As("avgage")).Group(u.Name).Having(u.WithContext(ctx).Columns(u.Age.Avg()).Gt(subQuery).Find()
    // SELECT AVG(age) as avgage FROM `users` GROUP BY `name` HAVING AVG(age) > (SELECT AVG(age) FROM `users` WHERE name LIKE "name%")
    
    // Select users with orders between 100 and 200
    subQuery1 := o.WithContext(ctx).Select(o.ID).Where(o.UserID.EqCol(u.ID), o.Amount.Gt(100))
    subQuery2 := o.WithContext(ctx).Select(o.ID).Where(o.UserID.EqCol(u.ID), o.Amount.Gt(200))
    u.WithContext(ctx).Exists(subQuery1).Not(u.WithContext(ctx).Exists(subQuery2)).Find()
    // SELECT * FROM `users` WHERE EXISTS (SELECT `orders`.`id` FROM `orders` WHERE `orders`.`user_id`= `users`.`id` AND `orders`.`amount` > 100 AND `orders`.`deleted_at` IS NULL) AND NOT EXISTS (SELECT `orders`.`id` FROM `orders` WHERE `orders`.`user_id` = `users`.`id` AND `orders`.`amount` > 200 AND `orders`.`deleted_at` IS NULL) AND `users`.`deleted_at` IS NULL
    
    
    //查询不存在赋值(不会创建)
    // User not found, initialize it with given conditions and Attrs
    u.WithContext(ctx).Attrs(field.Attrs(&model.User{Age: 20})).Where(u.Name.Eq("non_existing")).FirstOrInit()
    // SELECT * FROM USERS WHERE name = 'non_existing' ORDER BY id LIMIT 1;
    // user -> User{Name: "non_existing", Age: 20}
    
    // User not found, initialize it with given conditions and Attrs
    u.WithContext(ctx).Attrs(u.Age.Value(20).Where(u.Name.Eq("non_existing")).FirstOrInit()
    // SELECT * FROM USERS WHERE name = 'non_existing' ORDER BY id LIMIT 1;
    // user -> User{Name: "non_existing", Age: 20}
    
    // Found user with `name` = `gen`, attributes will be ignored
    u.WithContext(ctx).Attrs(field.Attrs(&model.User{Age: 20})).Where(u.Name.Eq("gen")).FirstOrInit()
    // SELECT * FROM USERS WHERE name = 'gen' ORDER BY id LIMIT 1;
    // user -> User{ID: 111, Name: "gen", Age: 18}
    
    //查询不存在则创建
    // User not found, initialize it with give conditions and Assign attributes
    u.WithContext(ctx).Assign(field.Attrs(&model.User{Age: 20})).Where(u.Name.Eq("non_existing")).FirstOrCreate()
    // SELECT * FROM users WHERE name = 'non_existing' ORDER BY id LIMIT 1;
    // INSERT INTO "users" (name, age) VALUES ("non_existing", 20);
    // user -> User{ID: 112, Name: "non_existing", Age: 20}
    
    // Found user with `name` = `gen`, update it with Assign attributes
    u.WithContext(ctx).Assign(field.Attrs(&model.User{Age: 20})).Where(u.Name.Eq("gen")).FirstOrCreate()
    // SELECT * FROM users WHERE name = 'gen' ORDER BY id LIMIT 1;
    // UPDATE users SET age=20 WHERE id = 111;
    // user -> User{ID: 111, Name: "gen", Age: 20}
    
    // Found user with `name` = `gen`, update it with Assign attributes
    u.WithContext(ctx).Assign(u.Age.Value(20)).Where(u.Name.Eq("gen")).FirstOrCreate()
    // SELECT * FROM users WHERE name = 'gen' ORDER BY id LIMIT 1;
    // UPDATE users SET age=20 WHERE id = 111;
    // user -> User{ID: 111, Name: "gen", Age: 20}
    }
    

    下一篇:GORM GEN的最佳实践

    相关文章

    Oracle如何使用授予和撤销权限的语法和示例
    Awesome Project: 探索 MatrixOrigin 云原生分布式数据库
    下载丨66页PDF,云和恩墨技术通讯(2024年7月刊)
    社区版oceanbase安装
    Oracle 导出CSV工具-sqluldr2
    ETL数据集成丨快速将MySQL数据迁移至Doris数据库

    发布评论