乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      Golang的ORM框架之gorm

       行者花雕 2022-02-18

      前言

      ORM全稱Object Relational Mapping,是把編程語(yǔ)言中的Object/Struct數(shù)據(jù)類型映射到關(guān)系數(shù)據(jù)庫(kù)中1張表,以下是詳細(xì)映射關(guān)系。

      結(jié)構(gòu)體------------     數(shù)據(jù)表
      
      結(jié)構(gòu)體實(shí)例----------    表中1條記錄
      
      結(jié)構(gòu)體字段------------  結(jié)構(gòu)體字段

       

      gorm簡(jiǎn)介

      面向github編程找一找Golang中比較流行的orm,

      注意Django的orm是包含在Django web框架中的,而gorm有點(diǎn)像Python中的sqlalchemy它不限制你必須要在某個(gè)web框架中使用它。

      gorm中文官方網(wǎng)站內(nèi)含十分齊全的中文文檔。

       

      本文將圍繞當(dāng)前最近版本gorm v1.20.8展開。

      go.mod

      module golang-gorm
      
      go 1.14
      
      require (
          github.com/go-sql-driver/mysql v1.5.0
          /driver/mysql v1.0.3
          /gorm v1.20.8
      )

       

      gorm安裝

      SET GOPROXY=https:// 
      go get -u github.com/jinzhu/gorm

       

      連接數(shù)據(jù)庫(kù)

      在golang中連接不同的數(shù)據(jù)就需要使用不同的driver驅(qū)動(dòng)。

      GORM 官方支持的數(shù)據(jù)庫(kù)類型有: MySQL, PostgreSQL, SQlite, SQL Server

      "/driver/mysql" //MySQL驅(qū)動(dòng)

      "/driver/sqlite"//sqllite的驅(qū)動(dòng)

      "/driver/postgres" //postgres的驅(qū)動(dòng)

      開始

      package main
      
      import (
      	"fmt"
      	"/driver/mysql" //MySQL驅(qū)動(dòng)
      	"/gorm"
      	"time"
      )
      
      func init() {
      	//配置數(shù)據(jù)連接:注意設(shè)置parseTime=true否則會(huì)報(bào)錯(cuò)!unsupported Scan 時(shí)間類型的字段
      	dbinfo := "zhanggen:xxoo@tcp(192.168.56.18:3306)/web?charset=utf8&parseTime=true&loc=Local"
      	db, err := gorm.Open(mysql.Open(dbinfo), &gorm.Config{})
      	//配置一下數(shù)據(jù)連接參數(shù)!
      	mySQL, err := db.DB()
      	if err != nil {
      		fmt.Println(err)
      	}
      	defer mySQL.Close()
      	//設(shè)置最大空閑連接
      	mySQL.SetMaxIdleConns(10)
      	//設(shè)置最大連接數(shù)
      	mySQL.SetMaxOpenConns(100)
      	//設(shè)置連接超時(shí)時(shí)間:1分鐘
      	mySQL.SetConnMaxLifetime(time.Minute)
      
      }
      

        

      Model定義

      我們?cè)趧?chuàng)建Table的時(shí)可以通過(guò)設(shè)置struct字段的tag,對(duì)數(shù) 表名、字段進(jìn)行屬性設(shè)置。

      結(jié)構(gòu)體

      package book
      
      import "time"
      
      type Book struct {
      	ID          uint       `gorm:"column:id;primaryKey"`
      	Title       string     `gorm:"column:title;not null;type:varchar(100);unique_index"` //指定數(shù)據(jù)庫(kù)列的數(shù)據(jù)類型
      	Author      string     `gorm:"column:author;not null;size:125"`             //設(shè)置Author在數(shù)據(jù)庫(kù)中不能為空,字段大小為255
      	Publishtime *time.Time `gorm:"column:publishtime"`
      }
      // 將默認(rèn)表面Book 的表名設(shè)置為book
      func (Book) TableName() string {
      	return "book"
      }
      

      --------------------------------

      package login
      
      //用戶表
      type UserInfo struct {
      	ID       uint   `gorm:"column:id;primaryKey"`
      	Username string `gorm:"column:username;unique;not null;index"`
      	Password string `gorm:"column:password;not null;"`
      }
      
      // 將 UserInfos 的表名設(shè)置為 `user`
      func (UserInfo) TableName() string {
      	return "user"
      }
      

        

      Mysql

      MariaDB [web]> desc book;
      +-------------+---------------------+------+-----+---------+----------------+
      | Field       | Type                | Null | Key | Default | Extra          |
      +-------------+---------------------+------+-----+---------+----------------+
      | id          | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment |
      | title       | varchar(100)        | NO   |     | NULL    |                |
      | author      | varchar(125)        | NO   |     | NULL    |                |
      | publishtime | datetime(3)         | YES  |     | NULL    |                |
      +-------------+---------------------+------+-----+---------+----------------+
      4 rows in set (0.00 sec)

      -------------------------------------

      MariaDB [web]> desc user;
      +----------+---------------------+------+-----+---------+----------------+
      | Field    | Type                | Null | Key | Default | Extra          |
      +----------+---------------------+------+-----+---------+----------------+
      | id       | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment |
      | username | varchar(191)        | NO   | UNI | NULL    |                |
      | password | longtext            | NO   |     | NULL    |                |
      +----------+---------------------+------+-----+---------+----------------+
      3 rows in set (0.00 sec)

       

      Django orm的差別

      當(dāng)我們Django的model中修改了表字段需要先make magrations生成操作,然后再make magirate去數(shù)據(jù)庫(kù)真正執(zhí)行這次magration。保證了數(shù)據(jù)庫(kù)的安全。

      而gorm只要你執(zhí)行db.AutoMigrate()就會(huì)實(shí)時(shí)修改表結(jié)構(gòu),但是當(dāng)你使用Django orm 修改了數(shù)據(jù)庫(kù)字段magration時(shí)經(jīng)常報(bào)錯(cuò)Exist table讓你不知所措。

       

      查看gorm操作日志 

      db.Debug可以幫助我們顯示gorm對(duì)數(shù)據(jù)庫(kù)的操作

      db.Debug().AutoMigrate(&User{})

      日志內(nèi)容

      [1.000ms] [rows:0] ALTER TABLE `users` MODIFY COLUMN `age` bigint DEFAULT 19

       

      增刪改查CURD

      立即執(zhí)行方法(Immediate Methods):查詢只有執(zhí)行了立即執(zhí)行函數(shù)才會(huì)去數(shù)據(jù)庫(kù)查詢 First/Find/FirstrOrInit/FirstOrCreate/

      內(nèi)聯(lián)條件 inline condition:就是把SQL查詢條件當(dāng)做參數(shù)傳遞到立即執(zhí)行函數(shù)中執(zhí)行。

      gorm支持使用String、Struct&Map作為條件進(jìn)行查詢已經(jīng)鏈樣操作。

       

      創(chuàng)建單條記錄

        /1.創(chuàng)建單條記錄
          u := User{Name: "Martin", Age: 19}
          result := Model.Create(&u)
          //返回插入數(shù)據(jù)的主鍵
          fmt.Println(u.ID)
          //返回的error
          fmt.Println(result.Error)
          //返回插入記錄的條數(shù)
          fmt.Println(result.RowsAffected)
          //如果記錄存在將不再重復(fù)創(chuàng)建
          result = Model.FirstOrCreate(&u)
          if result.RowsAffected == 0 {
              fmt.Println("記錄已經(jīng)存在!")
          }

       

      批量創(chuàng)建

      在生產(chǎn)環(huán)境之中如果你插入數(shù)據(jù)特別頻繁,可以使用批量插入的方式進(jìn)行優(yōu)化。如果數(shù)據(jù)沒有實(shí)時(shí)展示的要求。

          //批量創(chuàng)建
          var userList = []User{{Name: "jinzhu1"}, {Name: "jinzhu2"}, {Name: "jinzhu3"}}
          Model.Debug().Create(&userList)
          for _, user := range userList {
              fmt.Println(user.ID) // 1,2,3
          }

       

       

       查詢

      new和make區(qū)別:make給map/channel/slince申請(qǐng)內(nèi)存和容量返回值類型,new初始化基本類型string/int/結(jié)構(gòu)體返回指針類型的變量

       

      主鍵查詢

      Objects can be retrieved using primary key by using Inline Conditions.

      Be extra careful with strings to avoid SQL Injection, check out Security section for details 

      通過(guò)內(nèi)聯(lián)條件的方式,我們可以根據(jù)主鍵獲取到數(shù)據(jù)庫(kù)中的1/多條記錄。

      db.First(&user, 10)
      // SELECT * FROM users WHERE id = 10;
      
      db.First(&user, "10")
      // SELECT * FROM users WHERE id = 10;
      
      db.Find(&users, []int{1,2,3})
      // SELECT * FROM users WHERE id IN (1,2,3);

       

      一般查詢

          //1.普通查詢
          u := new(User)
          //查詢第1條數(shù)據(jù)
          Model.Debug().First(u) //SELECT * FROM `users` ORDER BY `users`.`id` LIMIT 1
          fmt.Println(u.Name)
          Model.Debug().First(u, 10)
          fmt.Println(u)
          //隨機(jī)獲取1條記錄
          u = new(User)         //new和make區(qū)別:make給map/channel/slince申請(qǐng)內(nèi)存和容量返回值類型,new初始化基本類型string/int/結(jié)構(gòu)體返回指針類型的變量
          Model.Debug().Take(u) //SELECT * FROM `users` LIMIT 1
          fmt.Println(u.Name)
          //獲取最后1條記錄
          u = new(User)
          Model.Last(u)
          fmt.Println(u.Name)
          //查詢表中所有記錄
          userList := []User{} //SELECT * FROM `users`
          Model.Debug().Find(&userList)
          fmt.Println(userList)

       

      Where 條件查詢

          //查詢所有匹配的記錄 然后獲取第1條
          u=new(User)
          Model.Debug().Where("name=?","jinzhu1").First(&u)//SELECT * FROM `users` WHERE name='jinzhu1' ORDER BY `users`.`id` LIMIT 1
          fmt.Println(u.Name)
          //查詢所有匹配的記錄,獲取所有
          userList=[]User{}
          Model.Debug().Where("name=?","Martin").Find(&userList)  //SELECT * FROM `users` WHERE name='Martin'
          fmt.Println(userList)
      
          userList=[]User{}
          Model.Debug().Where("name <>?","Martin").Find(&userList) //SELECT * FROM `users` WHERE name <>'Martin'
          fmt.Println(userList)
      
          userList=[]User{}
          Model.Debug().Where("name in?",[]string{"jinzhu"}).Find(&userList) //SELECT * FROM `users` WHERE name in('jinzhu')
          fmt.Println(userList)

       

      使用Struct & Map & 切片進(jìn)行查詢

      我們可使用結(jié)構(gòu)體、map、slice把搜索條件組合起來(lái)。

          //struct
          u = new(User)
          Model.Debug().Where(User{Name: "曹操", Age: 29}).First(&u)
          fmt.Println(u.Name)
          userList=[]User{}
          //map:我們可以使用map接收前端的json然后做組合搜索
          Model.Debug().Where(map[string]interface{}{"name": "希拉里", "age": 29}).Find(&userList) //SELECT * FROM `users` WHERE `users`.`name` = '曹操' AND `users`.`age` = 29 ORDER BY `users`.`id` LIMIT 1
          fmt.Println(userList)
          //主鍵的切片
          userList=[]User{}
          Model.Where([]int64{1,2,4,6}).Find(&userList)
          fmt.Println(userList)

       

       

      Not 條件查詢

      我們可以使用Where指定篩選條件,也可以使用Not排除一些條件。

          //not條件查詢
          u = new(User)
          userList = []User{}
          //1.不等于 <>
          //SELECT * FROM `users` WHERE `name` <> 'jinzhu' ORDER BY `users`.`id`
          Model.Debug().Not("name", "jinzhu").First(&u)
          fmt.Println(u.Name)
          //SELECT * FROM `users` WHERE `name` <> 'Martin'
          Model.Debug().Not("name", "Martin").Find(&userList)
          fmt.Println(userList)
          //2.不在x范圍之類 Not In
          userList = []User{}
          //SELECT * FROM `users` WHERE `users`.`id` NOT IN (1,4)
          Model.Debug().Not([]int64{1, 4}).Find(&userList)
          fmt.Println(userList)
          //SELECT * FROM `users`
          userList = []User{}
          Model.Debug().Not([]int64{}).Find(&userList)
          fmt.Println(userList)
          //4.執(zhí)行原生Sql
          userList = []User{}
          Model.Debug().Not("name=? or age<10", "Martin").Find(&userList)
          fmt.Println(userList)
          //5.not和where一樣同樣支持 通過(guò)struct/map/切片來(lái)組裝搜索條件
          userList = []User{}
          Model.Debug().Not(User{Name: "Martin", Age: 19}).Find(&userList)
          fmt.Println(userList)
      
          userList = []User{} //SELECT * FROM `users` WHERE (`age` <> 19 AND `name` <> 'jinzhu')
          Model.Debug().Not(map[string]interface{}{"name": "jinzhu", "age": 19}).Find(&userList)
          fmt.Println(userList)
      
          userList = []User{}
          Model.Debug().Not([]int64{1, 2}).Find(&userList) //SELECT * FROM `users` WHERE `users`.`id` NOT IN (1,2)
          fmt.Println(userList)

       

       

      Or條件查詢

      我可以使用Or連接2個(gè)搜索條件。

      //Or條件
          userList = []User{}
          Model.Where("name=?", "Martin").Or("name=?", "jinzhu").Find(&userList)
          fmt.Println(userList)
          //Or也支持Struct、map、slice進(jìn)行條件組成搜索
          userList = []User{}
          //SELECT * FROM `users` WHERE `users`.`name` = 'Martin' AND `users`.`age` = 29 OR (`users`.`name` = 'jinzhu' AND `users`.`age` = 29)
          Model.Debug().Where(User{Name: "Martin", Age: 29}).Or(User{Name: "jinzhu", Age: 29}).Find(&userList)
          fmt.Println(userList)
          //SELECT * FROM `users` WHERE `users`.`id` IN (1,2) OR `users`.`id` IN (5,4)
          Model.Debug().Where([]int64{1, 2}).Or([]int64{5,4}).Find(&userList)
          fmt.Println(userList)

       

      內(nèi)聯(lián)條件查詢

      通過(guò)以上大量的實(shí)驗(yàn)?zāi)銜?huì)發(fā)現(xiàn)我總會(huì)在Where/Not/Or里面組織搜索條件,然后再 .First/Find。

      這是Where/Not/Or中的SQL需要借助立即執(zhí)行方法 才真正把SQL發(fā)送到mysqld(服務(wù)端)執(zhí)行,然后返回值,我們聲明的變量才會(huì)獲取到值。

       

      您會(huì)發(fā)現(xiàn).Find()和.First()t這些立即執(zhí)行方法可以接收2個(gè)參數(shù)(dest interface{}, conds ...interface{})

      第1個(gè)參數(shù)用于接收和保存服務(wù)端(mysqld)返回的結(jié)果、第2個(gè)用于客戶端(MySQL)輸入SQL搜索條件。

      什么是內(nèi)聯(lián)條件查詢呢?

      就是我們?cè)诎呀邮詹樵兘Y(jié)果的變量、SQL查詢條件傳遞到.Find()/.First()/.Not()/.Or()這些立即執(zhí)行函數(shù)中執(zhí)行就屬于內(nèi)聯(lián)條件查詢。

      //內(nèi)聯(lián)條件
          //1.根據(jù)主鍵獲取記錄 (只適用于整形主鍵)
          u1 := new(User)
          Model.Debug().First(&u1, 1)
          fmt.Println(u1.Age)
          u1 = new(User)
          Model.Debug().First(&u1, "id = ?", 1)
          fmt.Println(u1.Name)
          //2.根據(jù)搜索條件獲取多條數(shù)據(jù)
          users := []User{}
          Model.Debug().Find(&users, "name = ?", "jinzhu")
          fmt.Println(users)
          //3.使用結(jié)構(gòu)體作為搜索參數(shù)
          users = []User{}
          Model.Debug().Find(&users, User{Age: 29})
          fmt.Println(users)
          //4.使用map組織搜索條件
          users = []User{}
          Model.Debug().Find(&users, map[string]interface{}{"age": "29"})
          fmt.Println(users)
          //5.使用slice作為搜索條件
          users=[]User{}
          Model.Debug().Find(&users,[]int64{1,6})
          fmt.Println(users)

       

      設(shè)置查詢選項(xiàng)

      GORM 提供了 SetGetInstanceSetInstanceGet 方法來(lái)允許用戶傳值給 勾子 或其他方法

      Gorm 中有一些特性用到了這種機(jī)制,如遷移表格時(shí)傳遞表格選項(xiàng)。

          err = db.Debug().Set("gorm:table_options","ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1").AutoMigrate(&User{})
          if err != nil {
              fmt.Println("創(chuàng)建表失敗",err)
          }
          fmt.Println("---------------------","創(chuàng)建表成功")

       

      我們?cè)诓樵?SQL是可以設(shè)置添加1個(gè)行鎖(在我查詢這條記錄的時(shí)候別人就無(wú)法修改這條數(shù)據(jù)了)

      users=[]User{}
      Model.Debug().Set("gorm:query_option","FOR UPDATE").Find(&users,[]int64{1,5})
      fmt.Println("--------",users)
      u1=new(User)
      Model.Set("gorm:query_option","FOR UPDATE").Debug().First(&u1,10)
      fmt.Println(u1.Name)
      

        

      FirstOrInit查詢

      gorm的核心功能就是把數(shù)據(jù)庫(kù)返回的1條記錄轉(zhuǎn)換成golang中的結(jié)構(gòu)體并對(duì)字段進(jìn)行賦值。

      如果在某些情況下我的SQL查詢沒有返回任何記錄,那我的stuct變量的全部字段就會(huì)使用零值。

      可以使用 Attrs和Assign方法對(duì) FirstOrInit返回的空記錄 進(jìn)行struct字段進(jìn)行賦值。

      attrs:獲取匹配的第1條記錄,否則根據(jù)給定的條件初始化一個(gè)新的對(duì)象 (僅支持 struct 和 map 條件)

      Assign:不管記錄是否找到,都將參數(shù)賦值給 struct變量。

        //FirstOrint
          //如果找到了就把數(shù)據(jù)庫(kù)返回的結(jié)果賦值給u2,如果沒有找到也不要緊把查詢條件賦值給u2進(jìn)行初始化。
          u2:=new(User)
          Model.FirstOrInit(u2,User{Name: "Martin"})
          fmt.Println(u2.Name)
          //在數(shù)據(jù)庫(kù)沒有返回查詢結(jié)果的情況下:使用Attrs指定Init時(shí)字段的值
          u2=new(User)
          Model.Attrs(User{Age:29} ).FirstOrInit(u2,User{Name: "Bob"})
          fmt.Println(u2.Name,u2.Age,u2.ID)
          //Assigin:不管數(shù)據(jù)庫(kù)有沒有返回查詢結(jié)果,在會(huì)初始化指定的字段
          u2=new(User)
          Model.Debug().Assign(User{Age: 21}).FirstOrInit(u2,User{Name:"抱墻"})
          fmt.Println(u2.Name,u2.Age)

       

      FirstOrCreate插入數(shù)據(jù)

      Attrs和Assign不僅可以對(duì)聲明的結(jié)構(gòu)體變量進(jìn)行初始化,還可以指定FirstOrCreate將要?jiǎng)?chuàng)建的記錄。

      FirstOrCreate:獲取匹配的第1條記錄, 否則根據(jù)給定的條件創(chuàng)建一個(gè)新的記錄 (僅支持 struct 和 map 條件)

      Attrs:如果記錄未找到,將使用attr中設(shè)置的參數(shù)創(chuàng)建 struct 和新記錄.

      Assign:不管記錄是否找到,都將參數(shù)賦值給 struct 并保存至數(shù)據(jù)庫(kù).

          //FirstOrCreate
          u3 := new(User)
          //如果SQL條件匹配到了記錄就返回原有記錄賦值給結(jié)構(gòu)體變量。
          Model.Debug().FirstOrCreate(u3, User{Name: "嬴政"})
          fmt.Println(u3.Age, u3.ID)
          //如果SQl查詢沒有匹配到記錄就 insert 1條新記錄,返回新記錄賦值給結(jié)構(gòu)體變量。
          u3 = new(User)
          Model.Debug().Where(User{Name: "嬴胡亥"}).FirstOrCreate(u3)
          fmt.Println(u3.ID)
      
          //Attrs
          //如果SQL匹配到記錄,返回原記錄并賦值給結(jié)構(gòu)體變量。(不使用Attrs(User{Age: 20})中設(shè)置的參數(shù))
          u3 = new(User)
          Model.Debug().Where(User{Name: "嬴胡亥"}).Attrs(User{Age: 20}).FirstOrCreate(u3)
          fmt.Println(u3.Name, u3.Age)
          //如果SQL沒有匹配到記錄,就使用Where(User{Name: "匹配不到嬴胡亥用戶"})和.Attrs(User{Age: 20})中的參數(shù), insert 1條新記錄,返回新記錄賦值給結(jié)構(gòu)體變量。
          u3 = new(User)
          Model.Debug().Where(User{Name: "匹配不到嬴胡亥用戶"}).Attrs(User{Age: 2000}).FirstOrCreate(u3)
          fmt.Println(u3.Name, u3.ID)
      
          //Assign
          //SQL匹配到記錄就更新原記錄(update not insert new record)
          u3 = new(User)
          Model.Debug().Where(User{Name: "嬴胡亥"}).Attrs(User{Age: 20}).FirstOrCreate(u3)
          fmt.Println(u3.Name, u3.Age)
          //沒有匹配到就使用Where(User{Name: "匹配不到嬴胡亥用戶"})和.Attrs(User{Age: 20})中的參數(shù),  insert new record。
          u3 = new(User)
          Model.Debug().Where(User{Name: "我不存在"}).Assign(User{Age: 90}).FirstOrCreate(u3)
          fmt.Println(u3.Name, u3.Age)

       

      子查詢

      db.Where("amount > ?", db.Table("orders").Select("AVG(amount)").Where("state = ?", "paid").SubQuery()).Find(&orders)
      // SELECT * FROM "orders"  WHERE "orders"."deleted_at" IS NULL AND (amount > (SELECT AVG(amount) FROM "orders"  WHERE (state = 'paid')));
      

       

      Select選擇字段

      Select,指定你想從數(shù)據(jù)庫(kù)中檢索出的字段,默認(rèn)會(huì)選擇全部字段。

            //Select,指定你想從數(shù)據(jù)庫(kù)中檢索出的字段,默認(rèn)會(huì)選擇全部字段。
      	users := []User{}
      	//SELECT id,name FROM `users`
      	Model.Debug().Select("id,name").Find(&users)
      	fmt.Println(users)
      	users = []User{}
      	//SELECT `name`,`age` FROM `users`
      	Model.Debug().Select([]string{"name","age"}).Find(&users)
      	fmt.Println(users)
      	users=[]User{}
      	Model.Debug().Table("users").Select("COALESCE(age,?)", 200)
      	fmt.Println(users)    
      

        

       

      排序查詢

       我們可以通過(guò)Order api對(duì)查詢的數(shù)據(jù)進(jìn)行排序

      	userList:=[]User{}
      	//SELECT * FROM `users` ORDER BY age desc, name
      	Model.Debug().Order("age desc, name").Find(&userList)
      	fmt.Println(userList)
      	// 多字段排序
      	userList=[]User{}
      	Model.Debug().Select("id,age").Order("id desc").Order("age").Find(&userList)
      	fmt.Println(userList)
      

        

      Limit & Offset

      分頁(yè)查詢Limit specify the max number of records to retrieve Offset specify the number of records to skip before starting to return the records

          //limit and offset
      	//返回3條數(shù)據(jù)
      	userList:=[]User{}
      	Model.Limit(3).Find(&userList)
      	fmt.Println(userList)
      	// 通過(guò) -1 消除 Limit 條件
      	Model.Limit(3).Find(&userList).Limit(-1).Find(&userList)
      	fmt.Println(userList)
      	//移動(dòng)到ID=2的記錄獲取2條,分頁(yè)就是這樣搞的!
      	Model.Debug().Offset(2).Limit(2).Find(&userList)
      	fmt.Println(userList)
      

        

      count獲取查詢總量

      Count,該 model 能獲取的記錄總數(shù)。Count 必須是鏈?zhǔn)讲樵兊淖詈笠粋€(gè)操作 ,因?yàn)樗鼤?huì)覆蓋前面的 SELECT,但如果里面使用了 count 時(shí)不會(huì)覆蓋

      count1:=new(int64)
      Model.Debug().Find(&userList).Count(count1)
      fmt.Println(*count1)
      

        

      Group&Having 

      分組和聚合

           //group by: SELECT name,sum(age) as total FROM `users` GROUP BY `name`
      	type groupByage struct {
      		Age  int
      		Total int
      	}
      	groupList :=[]groupByage{}
      	Model.Debug().Model(&User{}).Select("age,count(name) as total").Group("age").Find(&groupList)
      	fmt.Printf("%#v\n", groupList)
      
      
      	//haveing可以對(duì)group by 之后的結(jié)果,進(jìn)行進(jìn)一步篩選。
      	//SELECT name,sum(age) as total FROM `users` WHERE name LIKE '劉%' GROUP BY `name` HAVING total >= 50
      	type groupByname struct {
      		Name  string
      		Total int
      	}
      	groupList1:=[]groupByname{}
      	Model.Debug().Model(&User{}).Select("name,sum(age) as total").Where("name LIKE ?", "劉%").Group("name").Having("total >= ?",50).Find(&groupList1)
      	fmt.Println(groupList1)
      

        

      join連表

      type result struct {
        Name  string
        Email string
      }
      db.Model(&User{}).Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Scan(&result{})
      // SELECT users.name, emails.email FROM `users` left join emails on emails.user_id = users.id
      
      rows, err := db.Table("users").Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Rows()
      for rows.Next() {
        ...
      }
      
      db.Table("users").Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Scan(&results)
      
      // 帶參數(shù)的多表連接
      db.Joins("JOIN emails ON emails.user_id = users.id AND emails.email = ?", "jinzhu@example.org").Joins("JOIN credit_cards ON credit_cards.user_id = users.id").Where("credit_cards.number = ?", "411111111111").Find(&user)
      

        

       

      Pluck

      Query single column from database and scan into a slice, if you want to query multiple columns, use Select with Scan instead

      Pluck可以幫助我們獲取到table中的某1列數(shù)據(jù)并賦值給slice。

              //pluck獲取age列做位切片返回
      	var ageList []int64
      	Model.Debug().Model(&User{}).Pluck("age",&ageList)
      	fmt.Println(ageList)
      
      	nameList:=new([]string)
      	Model.Debug().Model(&User{}).Pluck("name",&nameList)
      	fmt.Println(nameList)        
      

       

      Scan

      Scan results into a struct work similar to Find

      Scan的功能類似于Find,可以把從數(shù)據(jù)庫(kù)中查詢到的結(jié)果映射到struct中。

      //scan的用法
          type scanResult struct {
              Name string
              Age  int64
          }
          //類似于First()的功能
          scanResultObj := new(scanResult)
          Model.Table("users").Select("name,age").Where("name = ?", "嬴政").Scan(scanResultObj)
          fmt.Println(scanResultObj)
          //類似于Find()功能
          scanResultList := new([]scanResult)
          Model.Table("users").Select("name,age").Where("name like ?", "劉%").Scan(scanResultList)
          fmt.Println(scanResultList)

       

      Scope查詢

      Scopes allow you to re-use commonly logic, the shared logic needs to defined as type func(*gorm.DB) *gorm.DB

      Scopes可以幫助我們把常用的查詢邏輯封裝到1個(gè)函數(shù)里面,后期使用查詢時(shí)Scope這個(gè)函數(shù)。

      //名字不為空
      func NameNotNull(db *gorm.DB) *gorm.DB {
          return db.Where("name is not null")
      }
      
      //查詢年齡>=18歲的用戶
      func AgeLe18(db *gorm.DB) *gorm.DB {
          return db.Where("age >= ?", 18)
      }
      
      //分頁(yè)查詢
      func PageData(start, count int) func(db *gorm.DB) *gorm.DB {
          return func(db *gorm.DB) *gorm.DB {
              return db.Offset(start).Limit(count)
          }
      }
      
          //scope
          //查詢姓名不為空 年齡>=18
          userList := new([]User)
          Model.Scopes(NameNotNull, AgeLe18).Find(userList)
          fmt.Println(userList)
          //分頁(yè)查詢
          Model.Scopes(PageData(5,10)).Find(userList)
          fmt.Println(userList)

       

      鏈?zhǔn)讲僮飨嚓P(guān)

       Django的Q查詢可以做組合查詢,gorm中的鏈?zhǔn)讲僮饕部梢浴?/p>

          var userlist []User
          contionChain:=Model.Debug().Not("name is null")
          contionChain.Where("name like ?","劉%")
          contionChain.Where("age >?",10)
          contionChain.Find(&userlist)
          fmt.Println(userlist)

       

      更新 update

       

      Save更新所有字段

        var userObj User
          Model.First(&userObj)
          fmt.Println(userObj)
          //save更新: 默認(rèn)會(huì)修改所有字段 
          userObj.Age=90
          //UPDATE `users` SET `id`=1,`created_at`='2020-12-24 05:29:33.978',`updated_at`='2020-12-24 13:35:08.695',`deleted_at`=NULL,`name`='特朗普',`age`=90,`active`=true WHERE `id` = 1
          Model.Debug().Save(userObj)

       

      Update更新1個(gè)字段

      Model(&userObj)我在Model中能傳了1個(gè)userObj,gorm會(huì)根據(jù)userObj中的id字段去數(shù)據(jù)庫(kù)where需要更新的記錄。

        //update:更新指定的字段
          //根據(jù)結(jié)構(gòu)體更新 1個(gè)字段
          Model.Debug().Model(&userObj).Update("name","唐納德.特朗普")
          //根據(jù)給定的條件更新 1個(gè)字段
          Model.Debug().Model(&userObj).Where("name = ?","唐納德.特朗普").Update("age",10)

       

      Updates同時(shí)更新多個(gè)字段

      我們可以給update方法傳1個(gè)map,同時(shí)更新多個(gè)字段。

      //更新多個(gè)字段 使用struct
          m1:=map[string]interface{}{
              "name":"唐納德.特朗普",
              "age":20,
          }
          //UPDATE `users` SET `age`=20,`name`='唐納德.特朗普',`updated_at`='2020-12-24 13:50:07.519' WHERE `id` = 1
          //注意:Model(&userObj)我在Model中能傳來(lái)1個(gè)userObj,gorm會(huì)根據(jù)userObj中的id字段去where需要更新的值
          Model.Debug().Model(&userObj).Updates(m1)

       

      Updates更新指定的字段

      有時(shí)我們接收到的map可能會(huì)包含一些我們不需要更新的字段,那么如何指定有效字段、排除無(wú)效字段呢?

          //updates:更新指定字段
          //指定age字段進(jìn)行更新
          Model.Debug().Model(&userObj).Select("age").Updates(map[string]interface{}{"name":"唐納德.-特朗普","age":9000,"active":false})
          //排除age字段進(jìn)行更新
          Model.Debug().Model(&userObj).Omit("age").Updates(map[string]interface{}{"name":"唐納德.-特朗普","age":9000,"active":false})
          

       

      UpdateColumns 

      UpdateColumns也叫無(wú)Hooks更新。

      上面的更新操作會(huì)自動(dòng)運(yùn)行 model 的 BeforeUpdateAfterUpdate 方法。

      更新 UpdatedAt 時(shí)間戳, 在更新時(shí)保存其 Associations, 如果你不想調(diào)用這些方法,你可以使用 UpdateColumn, UpdateColumns就不會(huì)更新UpdatedAt字段。

      //UpdateColumn
          Model.Debug().Model(&userObj).Update("name", "唐納德.特朗普")
          Model.Debug().Model(&userObj).UpdateColumns(map[string]interface{}{
              "name": "唐納德.-特朗普",
              "age":  200,
          })
          Model.Debug().Model(&userObj).UpdateColumns(User{Name:"唐納德.特朗普",Active: true})
          defer connectionPool.Close()

       

      批量更新多條記錄

       注意在批量更新的時(shí)候不會(huì)更新 UpdatedAt 字段。

          //批量更新
          AffectedRows:=Model.Debug().Table("users").Where("id in (?)", []int{1, 2}).Updates(map[string]interface{}{
              "age": 21,
          }).RowsAffected
          fmt.Println("更新的行數(shù)",AffectedRows)

       

      全表更新

      我想要1張表中的某個(gè)字段全部更新怎么辦?還記得Django中的F在原數(shù)據(jù)的基礎(chǔ)上+1?

        //全局更新
          //錯(cuò)誤的全局更新方式,之前是可以的??!
          err := Model.Model(&User{}).Update("name", "二狗").Error // 錯(cuò)誤的寫法??!gorm.ErrMissingWhereClause
          fmt.Println(err)
          //全局更新方式1
          Model.Debug().Exec("UPDATE users SET age = ?", "18")
          //讓user表中用戶年齡在原來(lái)的基礎(chǔ)上+2,Expr 子查詢
          Model.Debug().Session(&gorm.Session{AllowGlobalUpdate: true}).Model(User{}).Update("age", gorm.Expr("age+ ?", 100))

       

      刪除delete

      最后就是刪除了~

      刪除1條記錄

      我跟可以根據(jù)對(duì)象刪除一條記錄,注意必須指定對(duì)象的主鍵否則會(huì)觸發(fā) 批量 Delete,也可以根據(jù)主鍵直接刪除1條記錄。

        //根據(jù)對(duì)象刪除:刪除對(duì)象需要指定主鍵,否則會(huì)觸發(fā) 批量 Delete
          u:=new(User)
          u.ID=1
          Model.Debug().Delete(u)
          //根據(jù)主鍵刪除
          Model.Debug().Delete(&User{},10)
          //根據(jù)主鍵刪除多個(gè)
          Model.Debug().Delete(&User{},[]int{4,11})    

       

      批量刪除

      gorm中都是軟刪除。

          //2.批量刪除
          deletedUsers:=[]User{}
          Model.Debug().Where("name like ?","唐納德%").Delete(User{})
          Model.Debug().Delete(deletedUsers,"name like ?","嬴%")
          fmt.Println(deletedUsers)

       

      全表刪除

       清空表中的內(nèi)容

      //全局刪除
          //1.錯(cuò)誤的方式
          err:=Model.Delete(&User{}).Error
          fmt.Println(err)
          //正確方式
          Model.Where("1 = 1").Delete(&User{})
          Model.Exec("truncate table users")
          Model.Session(&gorm.Session{AllowGlobalUpdate: true}).Delete(&User{})

       

      表關(guān)聯(lián) 

      在關(guān)系型數(shù)據(jù)里表和表之間的關(guān)系:1對(duì)1(主鍵+外鍵聯(lián)合唯一)、1對(duì)多(外鍵)、多對(duì)多(中間增加1張記錄2個(gè)之間相互1對(duì)多關(guān)系的表),外鍵總在多的一方設(shè)置。

      平時(shí)我們討論表關(guān)系時(shí)有人會(huì)拋出 belongs to(屬于)、多對(duì)1、1對(duì)多這些概念,此時(shí)你千萬(wàn)別懵逼。其實(shí)反映到數(shù)據(jù)庫(kù)里還是外鍵。

      主表:在數(shù)據(jù)庫(kù)中建立的表格即Table,其中存在主鍵(primary key)用于與其它表相關(guān)聯(lián),并且作為在主表中的唯一性標(biāo)識(shí)。

      從表以主表的主鍵(primary key)值為外鍵 (Foreign Key)的表;從表可以通過(guò)外鍵與主表進(jìn)行關(guān)聯(lián)查詢,從表通過(guò)外鍵于主表進(jìn)行關(guān)聯(lián)查詢

      可能你理解的主和從表概念和綜上所述是相反的,沒關(guān)系這不影響技術(shù)愛好者之間的學(xué)習(xí)、交流,本文采用百度百科的定義的概念:外鍵在哪個(gè)表,那個(gè)表就是從表。

      以上2張表存在外鍵關(guān)聯(lián):

      一對(duì)多:從球隊(duì)角度來(lái)說(shuō)一個(gè)球隊(duì)擁有多個(gè)球員 即為一對(duì)多
      多對(duì)一:從球員角度來(lái)說(shuō)多個(gè)球員屬于一個(gè)球隊(duì) 即為多對(duì)一數(shù)據(jù)表間一對(duì)多關(guān)系如下圖:

      無(wú)論是1對(duì)多,還是多對(duì)1,本質(zhì)在數(shù)據(jù)庫(kù)里的體現(xiàn)還是1個(gè)外鍵。

       

      外鍵連表查詢

      以上我們上面大量篇幅說(shuō)主表從表,其實(shí)就是2個(gè)表存在外鍵關(guān)系

      根據(jù)自身業(yè)務(wù)需求設(shè)計(jì)外鍵就好了,我一般稱在從表使用外鍵查詢就屬于正向連表,否則就是反向連表查詢。

      一個(gè)外鍵引發(fā)了太多沒有意義的思考,好吧開始定義model和外鍵吧。

      使用默認(rèn)外鍵字段名稱

      type Role struct {
          gorm.Model
          Name         string `gorm:"not null"`
      }
      type User struct {
          gorm.Model
          Name         string  `gorm:"not null"`
          //RoleID:不是可以隨便寫的,指定User表和Role表名的ID是字段建立外鍵。
          RoleID    string  `gorm:"not null"`
          Role        Role
      }

       

      自定義外鍵名稱

      以上我們通過(guò)默認(rèn)的外鍵:使用擁有者(Role)的struct名+上主字段名做外鍵關(guān)聯(lián)到了主表。也可以在從表自定義外鍵的名稱。

      type Role struct {
          gorm.Model
          Name         string `gorm:"not null"`
      }
      type User struct {
          gorm.Model
          Name         string  `gorm:"not null"`
          //外鍵字段名稱叫role_id不好聽,我要叫role_refer 
          RoleRefer    string  `gorm:"not null"`
          Role        Role   `gorm:"foreignKey:RoleRefer"`
      }

       

      自定義外鍵字段

      我從表一定要外鍵到主表ID這個(gè)列?我想外鍵到其他列!

      type Role struct {
          gorm.Model
          Name         string `gorm:"not null"`
      }
      type User struct {
          gorm.Model
          Name         string  `gorm:"not null"`
          //從表外鍵字段名稱叫role_id不好聽,我要叫role_refer
          RoleRefer    string  `gorm:"not null"`
          //我想要外鍵到主表的Name字段
          Role        Role   `gorm:"foreignKey:RoleRefer;AssociationForeignKey:Name"`
      }

       

      最終定義1個(gè)模型

      type Role struct {
          gorm.Model
          Name         string `gorm:"not null"`
          //反向連表查詢用到Association(Users)
          Users      []User
      }
      type User struct {
          gorm.Model
          Name         string  `gorm:"not null"`
          //RoleID:與Role表名的ID是字段建立外鍵。正向連表查詢
          RoleID    string  `gorm:"not null"`
          Role        Role
      }

       

      正向和反向連表查詢

        //查詢id=1的用戶是什么角色?
          var user1 User
          //正向連表Preload
          Model.Preload("Role","id is not null").First(&user1,"id =?",2)
          fmt.Println("---",user1.Role)
      
          //在主表查詢id=2的角色被多少用戶使用?
          var role Role
          Model.First(&role,"id=?",2)
          fmt.Println(role.Name)
          //反向連表
          Model.Model(&role).Association("Users").Find(&role.Users)
          fmt.Println(role.Users)

       

      多對(duì)多查詢

      我現(xiàn)在想把用戶和角色變成多對(duì)多的關(guān)系。1個(gè)用戶可以有多個(gè)角色,1個(gè)角色也可以被多個(gè)用戶使用。這就不需要外鍵了,現(xiàn)在得使用1張中間關(guān)系表。

      type Role struct {
          gorm.Model
          Name         string `gorm:"not null"`
          Users       []User  `gorm:"many2many:user_roles;"`
      }
      type User
      struct { gorm.Model Name string `gorm:"not null"` Roles []Role `gorm:"many2many:user_roles;"` }

      多對(duì)多查詢最簡(jiǎn)單了

      var user1 User
          Model.Where("id = ?", "1").First(&user1)
          //查詢一下當(dāng)前用戶都有那些角色
          Model.Model(&user1).Association("Roles").Find(&user1.Roles)
          fmt.Println(user1.Roles)
      
          var role1 Role
          Model.Where("id = ?", "2").First(&role1)
          //查詢一下當(dāng)前角色都有那些用戶在使用
          Model.Model(&role1).Association("Users").Find(&role1.Users)
          fmt.Println(role1.Users)

       

       

       

       

       

       

       learnku

      從別人創(chuàng)建的表中導(dǎo)出model 

      參考

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多