gorm框架之自定义表名

本文解释了如何在GORM中通过实现TableName方法来自定义数据库表名,以及使用反射机制在解析模型时调用该方法。讨论了Kind和Type的区别,展示了如何通过Kind来识别数据类型。
摘要由CSDN通过智能技术生成

当然,只需要为定义好的数据表结构体实现一个 TableName 方法就好了。

对于新手来说,是比较好奇这个方法是怎么生效的,因为自己写的代码里其实并没有显式的调用这个方法的。

type User struct{
	Id int `gorm:"column:id;primaryKey;"`
	Name string `gorm:"name:id;"`
}

// 自定义表名
func (User) TableName() string {
	return "test_user"
}

在 gorm 里边,有一个 Tabler 接口,接口的也很简单,只需要自己的表结构体实现一个 TableName 方法就可以。

type Tabler interface {
	TableName() string
}

然后在解析表名的时候,会有相关逻辑判断对应的 model 是不是 Tabler 类型,是的话就会调用 TableName 方法(也就是我们自定义实现的那个方法名)来获取表名。

	...
    modelValue := reflect.New(modelType)
	tableName := namer.TableName(modelType.Name())
	if tabler, ok := modelValue.Interface().(Tabler); ok {
		tableName = tabler.TableName()
	}
	if tabler, ok := modelValue.Interface().(TablerWithNamer); ok {
		tableName = tabler.TableName(namer)
	}
	if en, ok := namer.(embeddedNamer); ok {
		tableName = en.Table
	}
    ...

当然,这里边涉及到一些反射相关的知识。

package main

import (
	"fmt"
	"reflect"
)

func main() {
	var x float64 = 3.4
	fmt.Println("type:", reflect.TypeOf(x)) // type: float64
	v := reflect.ValueOf(x)
	fmt.Println("value:", v)         // value: 3.4
	fmt.Println("type:", v.Type())   // type: float64
	fmt.Println("kind:", v.Kind())   // kind: float64
	fmt.Println("value:", v.Float()) // value: 3.4
	fmt.Println(v.Interface())
	fmt.Printf("value is %5.2e\n", v.Interface()) // value is 3.40e+00
	y, ok := v.Interface().(float64)
	if ok {
		fmt.Println(y) // 3.4
	}
	switch v.Interface().(type) {
	case int:
		fmt.Println("int type")
	case float32:
		fmt.Println("float32 type")
	case float64:
		fmt.Println("float64 type") // go there
	default:
		fmt.Println("unknown type")
	}
}

比如里边的 Kind 和 Type,看起来好像差不多,不过还是有区别的,我摘抄一段解释。

相较于 Type 而言,Kind 所表示的范畴更大。类似于家用电器(Kind)和电视机(Type)之间的对应关系。或者电视机(Kind)和 42 寸彩色电视机(Type)Type 是类型。Kind 是类别。Type 和 Kind 可能相同,也可能不同。通常基础数据类型的 Type 和 Kind 相同,自定义数据类型则不同。对于反射中的 kind 我们既可以通过 reflect.Type 来获取,也可以通过 reflect.Value 来获取。他们得到的值和类型均是相同的。

下面的例子其实比较清晰能说明了。

package main

import (
	"fmt"
	"reflect"
)

func main() {
	var x = struct {
		Name string
	}{Name: "Looking"}
	fmt.Println("type:", reflect.TypeOf(x)) // type: struct { Name string }
	v := reflect.ValueOf(x)
	fmt.Println("value:", v)       // value: {Looking}
	fmt.Println("type:", v.Type()) // type: struct { Name string }
	fmt.Println("kind:", v.Kind()) // kind: struct
}

看源码的话其实可以知道,Kind 类型目前就下面列举的这些。

type Kind uint

const (
	Invalid Kind = iota
	Bool
	Int
	Int8
	Int16
	Int32
	Int64
	Uint
	Uint8
	Uint16
	Uint32
	Uint64
	Uintptr
	Float32
	Float64
	Complex64
	Complex128
	Array
	Chan
	Func
	Interface
	Map
	Ptr
	Slice
	String
	Struct
	UnsafePointer
)

在使用 GORM 框架中,可以使用 Go 语言的协程(goroutine)来实现并发操作。下面是一个示例: ```go package main import ( "fmt" "github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/mysql" ) type User struct { ID int Name string } func main() { db, err := gorm.Open("mysql", "user:password@tcp(127.0.0.1:3306)/database?charset=utf8mb4&parseTime=True&loc=Local") if err != nil { panic("failed to connect database") } defer db.Close() // 创建一个协程来执行查询操作 go func() { var user User db.First(&user, 1) fmt.Println(user) }() // 创建另一个协程来执行插入操作 go func() { newUser := User{Name: "Alice"} db.Create(&newUser) }() // 等待一段时间,以确保协程有足够的时间执行 time.Sleep(time.Second) // 查询所有用户 var users []User db.Find(&users) fmt.Println(users) } ``` 在上面的示例中,我们使用了两个协程来执行数据库操作。第一个协程执行了查询操作,第二个协程执行了插入操作。通过使用协程,我们可以并发地执行这些操作,提高程序的性能。 需要注意的是,在使用协程时,我们需要确保数据库连接是线程安全的。在上面的示例中,我们使用了 `defer db.Close()` 来关闭数据库连接,以确保资源的释放。另外,为了确保协程有足够的时间执行,我们使用了 `time.Sleep(time.Second)` 来进行等待。 当然,具体的实现方式可能因为业务需求的不同而有所差异,上述示例仅供参考。在实际使用中,你可以根据自己的需求来选择合适的并发方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值