gorm 阅读4

var users []dot1xDataItem
dot1xDb.Where("user_name = ? AND client_macaddr = ?", "test1", "88:A4:C2:D9:27:AE").Find(&users)

来看看这行代码是怎样组装sql语句

// Where add conditions
//
// See the [docs] for details on the various formats that where clauses can take. By default, where clauses chain with AND.
//
//	// Find the first user with name jinzhu
//	db.Where("name = ?", "jinzhu").First(&user)
//	// Find the first user with name jinzhu and age 20
//	db.Where(&User{Name: "jinzhu", Age: 20}).First(&user)
//	// Find the first user with name jinzhu and age not equal to 20
//	db.Where("name = ?", "jinzhu").Where("age <> ?", "20").First(&user)
//
// [docs]: https://gorm.io/docs/query.html#Conditions
func (db *DB) Where(query interface{}, args ...interface{}) (tx *DB) {
	tx = db.getInstance()
	if conds := tx.Statement.BuildCondition(query, args...); len(conds) > 0 {
		tx.Statement.AddClause(clause.Where{Exprs: conds})
	}
	return
}

 

1、首先生成 build condition 

[]clause.Expression{clause.Expr{SQL: s, Vars: args}}
// Expr raw expression
type Expr struct {
	SQL                string
	Vars               []interface{}
	WithoutParentheses bool
}

2、AddClause   生成 stmt.Clauses[name] = c 对应的map

  设置stmt.Clauses[”WHERE“] = c
// Where where clause
type Where struct {
	Exprs []Expression // slice 变量
}

Exprs 为slice变量  也就是说可以是用多个where拼接

db.Where("name = ?", "jinzhu").Where("age <> ?", "20").First(&user)

3. Find 查找语句


// Find finds all records matching given conditions conds
func (db *DB) Find(dest interface{}, conds ...interface{}) (tx *DB) {
	tx = db.getInstance()
	if len(conds) > 0 {
		if exprs := tx.Statement.BuildCondition(conds[0], conds[1:]...); len(exprs) > 0 {
			tx.Statement.AddClause(clause.Where{Exprs: exprs})
		}
	}
	tx.Statement.Dest = dest
	return tx.callbacks.Query().Execute(tx)
}

看代码Find 也是支持where 条件查找的

db.Find(&users, []int{1,2,3})
// SELECT * FROM users WHERE id IN (1,2,3);
分析 

目标结构,根据其dest查找schema     tx.Statement.Dest = dest 

// Find finds all records matching given conditions conds
func (db *DB) Find(dest interface{}, conds ...interface{}) (tx *DB) {
	tx = db.getInstance()
	if len(conds) > 0 {
		if exprs := tx.Statement.BuildCondition(conds[0], conds[1:]...); len(exprs) > 0 {
			tx.Statement.AddClause(clause.Where{Exprs: exprs})
		}
	}
	tx.Statement.Dest = dest 
	return tx.callbacks.Query().Execute(tx)
}

 对于传进来的参数是var users []dot1xDataItem         Find(&users)

 

func (p *processor) Execute(db *DB) *DB {
	
	stmt              = db.Statement
	stmt.BuildClauses = p.Clauses
    stmt.Model = stmt.Dest
	
	// parse model values  虽然传进来的user是nil的slice
    //但是 &user 并不是nil
	if stmt.Model != nil {
		fmt.Printf(" stmt.Model:%+v  \n", stmt.Model)
		if err := stmt.Parse(stmt.Model); 
	}

	// assign stmt.ReflectValue
	if stmt.Dest != nil {
		fmt.Printf(" stmt.Dest:%+v  \n", stmt.Dest)
		stmt.ReflectValue = reflect.ValueOf(stmt.Dest)
		for stmt.ReflectValue.Kind() == reflect.Ptr {
			if stmt.ReflectValue.IsNil() && stmt.ReflectValue.CanAddr() {
				stmt.ReflectValue.Set(reflect.New(stmt.ReflectValue.Type().Elem()))
			}

			stmt.ReflectValue = stmt.ReflectValue.Elem()
		}
   /*
   (dlv) p  stmt.ReflectValue
reflect.Value {
        typ: *reflect.rtype {size: 24, ptrdata: 8, hash: 2766611295, tflag: tflagExtraStar (2), align: 8, fieldAlign: 8, kind: 23, equal: nil, gcdata: *1, str: 40247, ptrToThis: 66240},
        ptr: unsafe.Pointer(0xc000013278),
        flag: 407,}
kind 为23 slice
   */
		if !stmt.ReflectValue.IsValid() {
			db.AddError(ErrInvalidValue)
		}
	}
// stmt.ReflectValue  为[]user 类型的值
	for _, f := range p.fns {
		f(db)
	}

query

执行where之后以及执行find之前clause值为 如下:

Clauses: map[string]gorm.io/gorm/clause.Clause [
                "WHERE": (*"gorm.io/gorm/clause.Clause")(0xc00010dc88), 
        ],
        BuildClauses: []string len: 7, cap: 7, [
                "SELECT",
                "FROM",
                "WHERE",
                "GROUP BY",
                "ORDER BY",
                "LIMIT",
                "FOR",
        ],


func BuildQuerySQL(db *gorm.DB) {
	db.Statement.AddClauseIfNotExists(clause.From{}) // from 对应的 struct
    db.Statement.AddClauseIfNotExists(clauseSelect)  //select 对应的struct
    db.Statement.Build(db.Statement.BuildClauses...) // 根据db.Statement.BuildClauses 执行之前addClauses的build函数
    
    /*
      Clauses: map[string]gorm.io/gorm/clause.Clause [
                "WHERE": (*"gorm.io/gorm/clause.Clause")(0xc00010dc88), 
                "FROM": (*"gorm.io/gorm/clause.Clause")(0xc00010dce0), 
                "SELECT": (*"gorm.io/gorm/clause.Clause")(0xc00010dd38), 
        ],
        BuildClauses: []string len: 7, cap: 7, [
                "SELECT",
                "FROM",
                "WHERE",
                "GROUP BY",
                "ORDER BY",
                "LIMIT",
                "FOR",
        ],


    */
}
func Query(db *gorm.DB) {
	if db.Error == nil {
		BuildQuerySQL(db)
		fmt.Printf(" query  sql:%v \n", db.Statement.SQL.String())

		if !db.DryRun && db.Error == nil {
			rows, err := db.Statement.ConnPool.QueryContext(db.Statement.Context, db.Statement.SQL.String(), db.Statement.Vars...)
			if err != nil {
				db.AddError(err)
				return
			}
			defer func() {
				db.AddError(rows.Close())
			}()
			gorm.Scan(rows, db, 0)
		}
	}
}

 sql 语句执行完后返回rows

gorm.Scan(rows, db, 0)
db.scanIntoStruct(rows, elem, values, fields, joinFields) {
        for idx, field := range fields {
            values[idx] = field.NewValuePool.Get()
        rows.Scan(values...)
        for idx, field := range fields {
            field.Set(db.Statement.Context, reflectValue, values[idx])// 调用解析schema设置的set函数
            // release data to pool
		    field.NewValuePool.Put(values[idx])
        }
      
}
    
    //之前ParseWithSpecialTableName  解析dest 获取schema后设置schema 每个字段 的set 方法 获取value 方法
    //见 field.setupValuerAndSetter()

for initialized || rows.Next()  {
    db.scanIntoStruct(rows, elem, values, fields, joinFields)
    reflectValue = reflect.Append(reflectValue, elem)
}
db.Statement.ReflectValue.Set(reflectValue)

 

 

			
=> gorm.Scan(rows, db, mode) 将查询结构 rows 放入	Scan函数返回
		=> Scan(rows Rows, db *DB, mode ScanMode) 
				-> switch dest := db.Statement.Dest.(type) 根据 stmt 的 dest 类型设置怎么读 rows
				-> rows.Next()-> db.RowsAffected++ -> rows.Scan(values...)
				=> 类比原始 sql 操作
					for rows.Next() {
            err := rows.Scan(&id, &name)
            if err != nil {
              log.Fatal(err)
            }
            log.Println(id, name)
          }

 

posted @   codestacklinuxer  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示