You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
565 lines
20 KiB
565 lines
20 KiB
/*
|
|
* 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
|
|
if ast.IsExported(fieldName) { // 如果是可以输出的,不区分大小写
|
|
exportStructFieldMap[strings.ToLower(fieldName)] = field
|
|
// 如果是数据库字段
|
|
tagColumnValue := field.Tag.Get(tagColumnName)
|
|
if len(tagColumnValue) > 0 {
|
|
// dbColumnFieldMap[tagColumnValue] = field
|
|
// 使用数据库字段的小写,处理oracle和达梦数据库的sql返回值大写
|
|
tagColumnValueLower := strings.ToLower(tagColumnValue)
|
|
dbColumnFieldMap[tagColumnValueLower] = field
|
|
dbColumnFieldNameSlice = append(dbColumnFieldNameSlice, tagColumnValueLower)
|
|
// structFieldTagMap[fieldName] = tagColumnValue
|
|
}
|
|
|
|
} else { // 私有属性
|
|
privateStructFieldMap[strings.ToLower(fieldName)] = 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[exportCacheKey] = exportStructFieldMap
|
|
// cacheStructFieldInfoMap[privateCacheKey] = privateStructFieldMap
|
|
// cacheStructFieldInfoMap[dbColumnCacheKey] = dbColumnFieldMap
|
|
|
|
// cacheStructFieldTagInfoMap[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 {
|
|
// 先从本地缓存中查找
|
|
typeOf := reflect.TypeOf(entity)
|
|
valueOf := reflect.ValueOf(entity)
|
|
if typeOf.Kind() == reflect.Ptr { // 如果是指针
|
|
typeOf = typeOf.Elem()
|
|
valueOf = valueOf.Elem()
|
|
}
|
|
|
|
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(s interface{}, fieldName string) (interface{}, error) {
|
|
if s == nil || len(fieldName) < 1 {
|
|
return nil, errors.New("->structFieldValue数据为空")
|
|
}
|
|
// entity的s类型
|
|
valueOf := reflect.ValueOf(s)
|
|
|
|
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
|
|
}
|
|
|
|
// 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
|
|
|
|
// 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)
|
|
if !efOK {
|
|
return dbcfMap, errors.New("->getCacheStructFieldInfoMap-->dbColumnFieldMap取值转map[string]reflect.StructField类型异常")
|
|
}
|
|
return dbcfMap, nil
|
|
|
|
// return dbColumnFieldMap, nil
|
|
}
|
|
|
|
// columnAndValue 根据保存的对象,返回插入的语句,需要插入的字段,字段的值
|
|
func columnAndValue(entity interface{}) (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()
|
|
|
|
dbMap, err := getDBColumnFieldMap(&typeOf)
|
|
if err != nil {
|
|
return typeOf, nil, nil, err
|
|
}
|
|
dbSlice, err := getDBColumnFieldNameSlice(&typeOf)
|
|
if err != nil {
|
|
return typeOf, nil, nil, err
|
|
}
|
|
// 实体类公开字段的长度
|
|
fLen := len(dbMap)
|
|
// 长度不一致
|
|
if fLen-len(dbSlice) != 0 {
|
|
return typeOf, nil, nil, errors.New("->columnAndValue-->缓存的数据库字段和实体类字段不对应")
|
|
}
|
|
// 接收列的数组,这里是做一个副本,避免外部更改掉原始的列信息
|
|
columns := make([]reflect.StructField, 0, fLen)
|
|
// 接收值的数组
|
|
values := make([]interface{}, 0, fLen)
|
|
|
|
// 遍历所有数据库属性
|
|
for _, fieldName := range dbSlice {
|
|
//获取字段类型的Kind
|
|
// fieldKind := field.Type.Kind()
|
|
//if !allowTypeMap[fieldKind] { //不允许的类型
|
|
// continue
|
|
//}
|
|
field := dbMap[fieldName]
|
|
columns = append(columns, field)
|
|
// FieldByName方法返回的是reflect.Value类型,调用Interface()方法,返回原始类型的数据值.字段不会重名,不使用FieldByIndex()函数
|
|
value := valueOf.FieldByName(field.Name).Interface()
|
|
// 添加到记录值的数组
|
|
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()
|
|
// 字段的反射值
|
|
fieldValue := valueOfElem.FieldByName(field.Name)
|
|
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
|
|
}
|