1 Star 0 Fork 110

luomor/zorm

forked from springrain/zorm 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
structFieldInfo.go 23.24 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package zorm
import (
"context"
"database/sql"
"errors"
"fmt"
"go/ast"
"reflect"
"strings"
"sync"
)
const (
// tag标签的名称
tagColumnName = "column"
// 输出字段 缓存的前缀
exportPrefix = "_exportStructFields_"
// 私有字段 缓存的前缀
privatePrefix = "_privateStructFields_"
// 数据库列名 缓存的前缀
dbColumnNamePrefix = "_dbColumnName_"
// 数据库所有列名,经过排序 缓存的前缀
dbColumnNameSlicePrefix = "_dbColumnNameSlice_"
// field对应的column的tag值 缓存的前缀
structFieldTagPrefix = "_structFieldTag_"
// 数据库主键 缓存的前缀
// dbPKNamePrefix = "_dbPKName_"
)
// cacheStructFieldInfoMap 用于缓存反射的信息,sync.Map内部处理了并发锁
var cacheStructFieldInfoMap *sync.Map = &sync.Map{}
// var cacheStructFieldInfoMap = make(map[string]map[string]reflect.StructField)
// 用于缓存field对应的column的tag值
// var cacheStructFieldTagInfoMap = make(map[string]map[string]string)
// structFieldInfo 获取StructField的信息.只对struct或者*struct判断,如果是指针,返回指针下实际的struct类型
// 第一个返回值是可以输出的字段(首字母大写),第二个是不能输出的字段(首字母小写)
func structFieldInfo(typeOf *reflect.Type) error {
if typeOf == nil {
return errors.New("->structFieldInfo数据为空")
}
entityName := (*typeOf).String()
// 缓存的key
// 所有输出的属性,包含数据库字段,key是struct属性的名称,不区分大小写
exportCacheKey := exportPrefix + entityName
// 所有私有变量的属性,key是struct属性的名称,不区分大小写
privateCacheKey := privatePrefix + entityName
// 所有数据库的属性,key是数据库的字段名称,不区分大小写
dbColumnCacheKey := dbColumnNamePrefix + entityName
// 所有数据库字段名称的slice,经过排序,不区分大小写
dbColumnNameSliceCacheKey := dbColumnNameSlicePrefix + entityName
structFieldTagCacheKey := structFieldTagPrefix + entityName
// dbPKNameCacheKey := dbPKNamePrefix + entityName
// 缓存的数据库主键值
_, exportOk := cacheStructFieldInfoMap.Load(exportCacheKey)
//_, exportOk := cacheStructFieldInfoMap[exportCacheKey]
//如果存在值,认为缓存中有所有的信息,不再处理
if exportOk {
return nil
}
// 获取字段长度
fieldNum := (*typeOf).NumField()
// 如果没有字段
if fieldNum < 1 {
return errors.New("->structFieldInfo-->NumField entity没有属性")
}
// 声明所有字段的载体
var allFieldMap *sync.Map = &sync.Map{}
// anonymous := make([]reflect.StructField, 0)
// 缓存的数据
exportStructFieldMap := make(map[string]reflect.StructField)
privateStructFieldMap := make(map[string]reflect.StructField)
dbColumnFieldMap := make(map[string]reflect.StructField)
structFieldTagMap := make(map[string]string)
dbColumnFieldNameSlice := make([]string, 0)
// 遍历sync.Map,要求输入一个func作为参数
// 这个函数的入参、出参的类型都已经固定,不能修改
// 可以在函数体内编写自己的代码,调用map中的k,v
// var funcMapKV func(k, v interface{}) bool
funcMapKV := func(k, v interface{}) bool {
field := v.(reflect.StructField)
fieldName := field.Name
fieldNameLower := strings.ToLower(fieldName)
if ast.IsExported(fieldName) { // 如果是可以输出的,不区分大小写
exportStructFieldMap[fieldNameLower] = field
// 如果是数据库字段
tagColumnValue := field.Tag.Get(tagColumnName)
if tagColumnValue != "" {
// dbColumnFieldMap[tagColumnValue] = field
// 使用数据库字段的小写,处理oracle和达梦数据库的sql返回值大写
tagColumnValueLower := strings.ToLower(tagColumnValue)
dbColumnFieldMap[tagColumnValueLower] = field
dbColumnFieldNameSlice = append(dbColumnFieldNameSlice, tagColumnValueLower)
// 记录字段名称和tag里字段名的对应关系
structFieldTagMap[fieldName] = tagColumnValue
}
} else { // 私有属性
privateStructFieldMap[fieldNameLower] = field
}
return true
}
// 并发锁,用于处理slice并发append
var lock sync.Mutex
// funcRecursiveAnonymous 递归调用struct的匿名属性,就近覆盖属性
var funcRecursiveAnonymous func(allFieldMap *sync.Map, anonymous *reflect.StructField)
funcRecursiveAnonymous = func(allFieldMap *sync.Map, anonymous *reflect.StructField) {
// 字段类型
anonymousTypeOf := anonymous.Type
if anonymousTypeOf.Kind() == reflect.Ptr {
// 获取指针下的Struct类型
anonymousTypeOf = anonymousTypeOf.Elem()
}
// 只处理Struct类型
if anonymousTypeOf.Kind() != reflect.Struct {
return
}
// 获取字段长度
fieldNum := anonymousTypeOf.NumField()
// 如果没有字段
if fieldNum < 1 {
return
}
// 遍历所有字段
for i := 0; i < fieldNum; i++ {
anonymousField := anonymousTypeOf.Field(i)
if anonymousField.Anonymous { // 匿名struct里自身又有匿名struct
funcRecursiveAnonymous(allFieldMap, &anonymousField)
} else if _, ok := allFieldMap.Load(anonymousField.Name); !ok { // 普通命名字段,而且没有记录过
allFieldMap.Store(anonymousField.Name, anonymousField)
lock.Lock()
funcMapKV(anonymousField.Name, anonymousField)
lock.Unlock()
}
}
}
// 遍历所有字段,记录匿名属性
for i := 0; i < fieldNum; i++ {
field := (*typeOf).Field(i)
if field.Anonymous { // 如果是匿名的
funcRecursiveAnonymous(allFieldMap, &field)
} else if _, ok := allFieldMap.Load(field.Name); !ok { // 普通命名字段,而且没有记录过
allFieldMap.Store(field.Name, field)
lock.Lock()
funcMapKV(field.Name, field)
lock.Unlock()
}
}
// allFieldMap.Range(f)
// 加入缓存
cacheStructFieldInfoMap.Store(exportCacheKey, exportStructFieldMap)
cacheStructFieldInfoMap.Store(privateCacheKey, privateStructFieldMap)
cacheStructFieldInfoMap.Store(dbColumnCacheKey, dbColumnFieldMap)
cacheStructFieldInfoMap.Store(structFieldTagCacheKey, structFieldTagMap)
// 不按照字母顺序,按照反射获取的Struct属性顺序,生成insert语句和update语句
// sort.Strings(dbColumnFieldNameSlice)
cacheStructFieldInfoMap.Store(dbColumnNameSliceCacheKey, dbColumnFieldNameSlice)
return nil
}
// setFieldValueByColumnName 根据数据库的字段名,找到struct映射的字段,并赋值
func setFieldValueByColumnName(entity interface{}, columnName string, value interface{}) error {
valueOf := reflect.ValueOf(entity)
if valueOf.Kind() == reflect.Ptr { // 如果是指针
valueOf = valueOf.Elem()
}
typeOf := valueOf.Type()
// 先从本地缓存中查找
dbMap, err := getDBColumnFieldMap(&typeOf)
if err != nil {
return err
}
f, ok := (*dbMap)[strings.ToLower(columnName)]
if ok { // 给主键赋值
valueOf.FieldByName(f.Name).Set(reflect.ValueOf(value))
}
return nil
}
// structFieldValue 获取指定字段的值
func structFieldValue(entity interface{}, fieldName string) (interface{}, error) {
if entity == nil || fieldName == "" {
return nil, errors.New("->structFieldValue数据为空")
}
// entity的s类型
valueOf := reflect.ValueOf(entity)
kind := valueOf.Kind()
if !(kind == reflect.Ptr || kind == reflect.Struct) {
return nil, errors.New("->structFieldValue必须是Struct或者*Struct类型")
}
if kind == reflect.Ptr {
// 获取指针下的Struct类型
valueOf = valueOf.Elem()
if valueOf.Kind() != reflect.Struct {
return nil, errors.New("->structFieldValue必须是Struct或者*Struct类型")
}
}
// FieldByName方法返回的是reflect.Value类型,调用Interface()方法,返回原始类型的数据值
value := valueOf.FieldByName(fieldName).Interface()
return value, nil
}
// getDBColumnExportFieldMap 获取实体类的数据库字段,key是数据库的字段名称.同时返回所有的字段属性的map,key是实体类的属性.不区分大小写
func getDBColumnExportFieldMap(typeOf *reflect.Type) (*map[string]reflect.StructField, *map[string]reflect.StructField, error) {
dbColumnFieldMap, err := getCacheStructFieldInfoMap(typeOf, dbColumnNamePrefix)
if err != nil {
return nil, nil, err
}
exportFieldMap, err := getCacheStructFieldInfoMap(typeOf, exportPrefix)
return dbColumnFieldMap, exportFieldMap, err
}
// getDBColumnFieldMap 获取实体类的数据库字段,key是数据库的字段名称.不区分大小写
func getDBColumnFieldMap(typeOf *reflect.Type) (*map[string]reflect.StructField, error) {
return getCacheStructFieldInfoMap(typeOf, dbColumnNamePrefix)
}
// getDBColumnFieldNameSlice 获取实体类的数据库字段,经过排序,key是数据库的字段名称.不区分大小写,
func getDBColumnFieldNameSlice(typeOf *reflect.Type) (*[]string, error) {
dbColumnFieldSlice, dbmapErr := getCacheStructFieldInfo(typeOf, dbColumnNameSlicePrefix)
if dbmapErr != nil {
return nil, fmt.Errorf("->getDBColumnFieldNameSlice-->getCacheStructFieldInfo()取值错误:%w", dbmapErr)
}
dbcfSlice, efOK := (*dbColumnFieldSlice).([]string)
if !efOK {
return &dbcfSlice, errors.New("->getDBColumnFieldNameSlice-->dbColumnFieldSlice取值转[]string类型异常")
}
return &dbcfSlice, nil
}
// getStructFieldTagMap 获取实体类的数据库字段Tag的map,fieldName-->tagValue
func getStructFieldTagMap(typeOf *reflect.Type) (*map[string]string, error) {
structFieldTagMap, dbmapErr := getCacheStructFieldInfo(typeOf, structFieldTagPrefix)
if dbmapErr != nil {
return nil, fmt.Errorf("->getStructFieldTagMap-->getCacheStructFieldInfo()取值错误:%w", dbmapErr)
}
tagMap, efOK := (*structFieldTagMap).(map[string]string)
if !efOK {
return &tagMap, errors.New("->getStructFieldTagMap-->structFieldTagMap取值转map[string]string类型异常")
}
return &tagMap, nil
}
// getCacheStructFieldInfo 根据类型和key,获取缓存的数据字段信息slice,已经排序
func getCacheStructFieldInfo(typeOf *reflect.Type, keyPrefix string) (*interface{}, error) {
if typeOf == nil {
return nil, errors.New("->getCacheStructFieldInfo-->typeOf不能为空")
}
key := keyPrefix + (*typeOf).String()
dbColumnFieldMap, dbOk := cacheStructFieldInfoMap.Load(key)
// dbColumnFieldMap, dbOk := cacheStructFieldInfoMap[key]
if !dbOk { // 缓存不存在
// 获取实体类的输出字段和私有 字段
err := structFieldInfo(typeOf)
if err != nil {
return nil, err
}
dbColumnFieldMap, dbOk = cacheStructFieldInfoMap.Load(key)
// dbColumnFieldMap, dbOk = cacheStructFieldInfoMap[key]
if !dbOk {
return nil, errors.New("->getCacheStructFieldInfo-->cacheStructFieldInfoMap.Load()获取数据库字段dbColumnFieldMap异常")
}
}
return &dbColumnFieldMap, nil
}
// getCacheStructFieldInfoMap 根据类型和key,获取缓存的字段信息
func getCacheStructFieldInfoMap(typeOf *reflect.Type, keyPrefix string) (*map[string]reflect.StructField, error) {
dbColumnFieldMap, dbmapErr := getCacheStructFieldInfo(typeOf, keyPrefix)
if dbmapErr != nil {
return nil, fmt.Errorf("->getCacheStructFieldInfoMap-->getCacheStructFieldInfo()取值错误:%w", dbmapErr)
}
// dbcfMap, efOK := dbColumnFieldMap.(*map[string]reflect.StructField)
dbcfMap, efOK := (*dbColumnFieldMap).(map[string]reflect.StructField)
if !efOK {
return &dbcfMap, errors.New("->getCacheStructFieldInfoMap-->dbColumnFieldMap取值转map[string]reflect.StructField类型异常")
}
return &dbcfMap, nil
}
// columnAndValue 根据保存的对象,返回插入的语句,需要插入的字段,字段的值
func columnAndValue(ctx context.Context, entity IEntityStruct, onlyUpdateNotZero bool) (*reflect.Type, *[]reflect.StructField, *[]interface{}, error) {
typeOf, checkerr := checkEntityKind(entity)
if checkerr != nil {
return typeOf, nil, nil, checkerr
}
// 获取实体类的反射,指针下的struct
valueOf := reflect.ValueOf(entity).Elem()
// reflect.Indirect
// 先从本地缓存中查找
// typeOf := reflect.TypeOf(entity).Elem()
dbColumnFieldMap, err := getDBColumnFieldMap(typeOf)
if err != nil {
return typeOf, nil, nil, err
}
dbColumnFieldNameSlice, err := getDBColumnFieldNameSlice(typeOf)
if err != nil {
return typeOf, nil, nil, err
}
// 数据库字段的长度
fLen := len(*dbColumnFieldMap)
/*
// 长度不一致
if fLen-len(*dbColumnFieldNameSlice) != 0 {
return typeOf, nil, nil, errors.New("->columnAndValue-->缓存的数据库字段和实体类字段不对应")
}
*/
// 接收列的数组,这里是做一个副本,避免外部更改掉原始的列信息
columns := make([]reflect.StructField, 0, fLen)
// 接收值的数组
values := make([]interface{}, 0, fLen)
//Update仅更新指定列
var onlyUpdateColsMap map[string]bool
//UpdateNotZero必须更新指定列
var mustUpdateColsMap map[string]bool
//默认值的map
var defaultValueMap map[string]interface{}
ctxValueMap := ctx.Value(contextDefaultValueKey)
if ctxValueMap != nil {
defaultValueMap = ctxValueMap.(map[string]interface{})
} else {
defaultValueMap = entity.GetDefaultValue()
}
if onlyUpdateNotZero { //只更新非零值时,需要考虑mustUpdateCols
mustUpdateCols := ctx.Value(contextMustUpdateColsValueKey)
if mustUpdateCols != nil { //指定了仅更新的列
mustUpdateColsMap = mustUpdateCols.(map[string]bool)
if mustUpdateColsMap != nil {
//添加主键
mustUpdateColsMap[strings.ToLower(entity.GetPKColumnName())] = true
}
}
} else { //update 更新全部字段时,需要考虑onlyUpdateCols
onlyUpdateCols := ctx.Value(contextOnlyUpdateColsValueKey)
if onlyUpdateCols != nil { //指定了仅更新的列
onlyUpdateColsMap = onlyUpdateCols.(map[string]bool)
if onlyUpdateColsMap != nil {
//添加主键
onlyUpdateColsMap[strings.ToLower(entity.GetPKColumnName())] = true
}
}
}
// 遍历所有数据库字段名,小写的
for _, columnNameLower := range *dbColumnFieldNameSlice {
//获取字段类型的Kind
// fieldKind := field.Type.Kind()
//if !allowTypeMap[fieldKind] { //不允许的类型
// continue
//}
//指定仅更新的列,当前列不用更新
if onlyUpdateColsMap != nil && (!onlyUpdateColsMap[columnNameLower]) {
continue
}
field := (*dbColumnFieldMap)[columnNameLower]
var value interface{}
fv := valueOf.FieldByName(field.Name)
//默认值
isDefaultValue := false
var defaultValue interface{}
if defaultValueMap != nil {
defaultValue, isDefaultValue = defaultValueMap[field.Name]
}
//必须更新的字段
isMustUpdate := false
if mustUpdateColsMap != nil {
isMustUpdate = mustUpdateColsMap[columnNameLower]
}
isZero := fv.IsZero()
// FieldByName方法返回的是reflect.Value类型,调用Interface()方法,返回原始类型的数据值.字段不会重名,不使用FieldByIndex()函数
if isDefaultValue && isZero { //如果有默认值,并且fv是零值,等于默认值
value = defaultValue
} else if onlyUpdateNotZero && !isMustUpdate && isZero { //如果只更新不为零值的,并且不是mustUpdateCols
continue
} else if field.Type.Kind() == reflect.Ptr { // 如果是指针类型
if !fv.IsNil() { // 如果不是nil值
value = fv.Elem().Interface()
} else {
value = nil
}
} else {
value = fv.Interface()
}
//添加列
columns = append(columns, field)
// 添加到记录值的数组
values = append(values, value)
}
// 缓存数据库的列
return typeOf, &columns, &values, nil
}
// entityPKFieldName 获取实体类主键属性名称
func entityPKFieldName(entity IEntityStruct, typeOf *reflect.Type) (string, error) {
//检查是否是指针对象
//typeOf, checkerr := checkEntityKind(entity)
//if checkerr != nil {
// return "", checkerr
//}
// 缓存的key,TypeOf和ValueOf的String()方法,返回值不一样
// typeOf := reflect.TypeOf(entity).Elem()
dbMap, err := getDBColumnFieldMap(typeOf)
if err != nil {
return "", err
}
field := (*dbMap)[strings.ToLower(entity.GetPKColumnName())]
return field.Name, nil
}
// checkEntityKind 检查entity类型必须是*struct类型或者基础类型的指针
func checkEntityKind(entity interface{}) (*reflect.Type, error) {
if entity == nil {
return nil, errors.New("->checkEntityKind参数不能为空,必须是*struct类型或者基础类型的指针")
}
typeOf := reflect.TypeOf(entity)
if typeOf.Kind() != reflect.Ptr { // 如果不是指针
return nil, errors.New("->checkEntityKind必须是*struct类型或者基础类型的指针")
}
typeOf = typeOf.Elem()
//if !(typeOf.Kind() == reflect.Struct || allowBaseTypeMap[typeOf.Kind()]) { //如果不是指针
// return nil, errors.New("checkEntityKind必须是*struct类型或者基础类型的指针")
//}
return &typeOf, nil
}
// sqlRowsValues 包装接收sqlRows的Values数组,反射rows屏蔽数据库null值,兼容单个字段查询和Struct映射
// fix:converting NULL to int is unsupported
// 当读取数据库的值为NULL时,由于基本类型不支持为NULL,通过反射将未知driver.Value改为interface{},不再映射到struct实体类
// 感谢@fastabler提交的pr
// oneColumnScanner 只有一个字段,而且可以直接Scan,例如string或者[]string,不需要反射StructType进行处理
func sqlRowsValues(ctx context.Context, dialect string, valueOf *reflect.Value, typeOf *reflect.Type, rows *sql.Rows, driverValue *reflect.Value, columnTypes []*sql.ColumnType, entity interface{}, dbColumnFieldMap, exportFieldMap *map[string]reflect.StructField) error {
if entity == nil && valueOf == nil {
return errors.New("->sqlRowsValues-->valueOfElem为nil")
}
var valueOfElem reflect.Value
if entity == nil && valueOf != nil {
valueOfElem = valueOf.Elem()
}
ctLen := len(columnTypes)
// 声明载体数组,用于存放struct的属性指针
// Declare a carrier array to store the attribute pointer of the struct
values := make([]interface{}, ctLen)
// 记录需要类型转换的字段信息
var fieldTempDriverValueMap map[*sql.ColumnType]*driverValueInfo
if iscdvm {
fieldTempDriverValueMap = make(map[*sql.ColumnType]*driverValueInfo)
}
var err error
var customDriverValueConver ICustomDriverValueConver
var converOK bool
for i, columnType := range columnTypes {
if iscdvm {
databaseTypeName := strings.ToUpper(columnType.DatabaseTypeName())
// 根据接收的类型,获取到类型转换的接口实现,优先匹配指定的数据库类型
customDriverValueConver, converOK = customDriverValueMap[dialect+"."+databaseTypeName]
if !converOK {
customDriverValueConver, converOK = customDriverValueMap[databaseTypeName]
}
}
dv := driverValue.Index(i)
if dv.IsValid() && dv.InterfaceData()[0] == 0 { // 该字段的数据库值是null,取默认值
values[i] = new(interface{})
continue
} else if converOK { // 如果是需要转换的字段
// 获取字段类型
var structFieldType *reflect.Type
if entity != nil { // 查询一个字段,并且可以直接接收
structFieldType = typeOf
} else { // 如果是struct类型
field, err := getStructFieldByColumnType(columnType, dbColumnFieldMap, exportFieldMap)
if err != nil {
return err
}
if field != nil { // 存在这个字段
vtype := field.Type
structFieldType = &vtype
}
}
tempDriverValue, err := customDriverValueConver.GetDriverValue(ctx, columnType, structFieldType)
if err != nil {
return err
}
if tempDriverValue == nil {
return errors.New("->sqlRowsValues-->customDriverValueConver.GetDriverValue返回的driver.Value不能为nil")
}
values[i] = tempDriverValue
// 如果需要类型转换
dvinfo := driverValueInfo{}
dvinfo.customDriverValueConver = customDriverValueConver
// dvinfo.columnType = columnType
dvinfo.structFieldType = structFieldType
dvinfo.tempDriverValue = tempDriverValue
fieldTempDriverValueMap[columnType] = &dvinfo
continue
} else if entity != nil { // 查询一个字段,并且可以直接接收
values[i] = entity
continue
} else {
field, err := getStructFieldByColumnType(columnType, dbColumnFieldMap, exportFieldMap)
if err != nil {
return err
}
if field == nil { // 如果不存在这个字段
values[i] = new(interface{})
} else {
// fieldType := refPV.FieldByName(field.Name).Type()
// v := reflect.New(field.Type).Interface()
var v interface{}
// 字段的反射值
fieldValue := valueOfElem.FieldByName(field.Name)
if fieldValue.Kind() == reflect.Ptr { // 如果是指针类型
// 反射new一个对应类型的指针
newValue := reflect.New(fieldValue.Type().Elem())
// 反射赋值到字段值
fieldValue.Set(newValue)
// 获取字段值
v = fieldValue.Interface()
} else {
v = fieldValue.Addr().Interface()
}
// v := new(interface{})
values[i] = v
}
}
}
err = rows.Scan(values...)
if err != nil {
return err
}
if len(fieldTempDriverValueMap) < 1 {
return err
}
// 循环需要替换的值
for columnType, driverValueInfo := range fieldTempDriverValueMap {
// 根据列名,字段类型,新值 返回符合接收类型值的指针,返回值是个指针,指针,指针!!!!
// typeOf := fieldValue.Type()
rightValue, errConverDriverValue := driverValueInfo.customDriverValueConver.ConverDriverValue(ctx, columnType, driverValueInfo.tempDriverValue, driverValueInfo.structFieldType)
if errConverDriverValue != nil {
errConverDriverValue = fmt.Errorf("->sqlRowsValues-->customDriverValueConver.ConverDriverValue错误:%w", errConverDriverValue)
FuncLogError(ctx, errConverDriverValue)
return errConverDriverValue
}
if entity != nil { // 查询一个字段,并且可以直接接收
// entity = rightValue
// valueOfElem.Set(reflect.ValueOf(rightValue).Elem())
reflect.ValueOf(entity).Elem().Set(reflect.ValueOf(rightValue).Elem())
continue
} else { // 如果是Struct类型接收
field, err := getStructFieldByColumnType(columnType, dbColumnFieldMap, exportFieldMap)
if err != nil {
return err
}
if field != nil { // 如果存在这个字段
// 字段的反射值
fieldValue := valueOfElem.FieldByName(field.Name)
// 给字段赋值
fieldValue.Set(reflect.ValueOf(rightValue).Elem())
}
}
}
return err
}
// getStructFieldByColumnType 根据ColumnType获取StructField对象,兼容驼峰
func getStructFieldByColumnType(columnType *sql.ColumnType, dbColumnFieldMap *map[string]reflect.StructField, exportFieldMap *map[string]reflect.StructField) (*reflect.StructField, error) {
columnName := strings.ToLower(columnType.Name())
// columnName := "test"
// 从缓存中获取列名的field字段
// Get the field field of the column name from the cache
field, fok := (*dbColumnFieldMap)[columnName]
if !fok {
field, fok = (*exportFieldMap)[columnName]
if !fok {
// 尝试驼峰
cname := strings.ReplaceAll(columnName, "_", "")
field, fok = (*exportFieldMap)[cname]
}
}
if fok {
return &field, nil
}
return nil, nil
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/luomor/zorm.git
git@gitee.com:luomor/zorm.git
luomor
zorm
zorm
master

搜索帮助