geektutu / blog

极客兔兔的博客,Coding Coding 创建有趣的开源项目。
https://geektutu.com
Apache License 2.0
167 stars 21 forks source link

动手写ORM框架 - GeeORM第二天 对象表结构映射 | 极客兔兔 #73

Open geektutu opened 4 years ago

geektutu commented 4 years ago

https://geektutu.com/post/geeorm-day2.html

7天用 Go语言/golang 从零实现 ORM 框架 GeeORM 教程(7 days implement golang object relational mapping framework from scratch tutorial),动手写 ORM 框架,参照 gorm, xorm 的实现。使用反射(reflect)获取任意 struct 对象的名称和字段,映射为数据中的表;使用 dialect 隔离不同数据库之间的差异,便于扩展;数据库表的创建(create)、删除(drop)。

avrilko-go commented 4 years ago

你好,我想问一下 var _ Dialect = (*sqlite3)(nil) 这一步的作用是什么呢?

geektutu commented 4 years ago

你好,我想问一下 var _ Dialect = (*sqlite3)(nil) 这一步的作用是什么呢?

参考 Go 语言简明教程#6.2 接口(interfaces)issues/10

walkmiao commented 4 years ago

Dialect 方言---用来处理不同数据库的类型 这个名字取的值得学习

walkmiao commented 4 years ago

func (s *sqlite3) DataTypeOf(typ reflect.Value) string 这个函数里 typ 的类型可以为reflect.Vaule,reflect.Type甚至是reflect.StructField。请教下如果不是为了利用反射修改值这种情况,其他几种方式是不是都可以任意使用?

walkmiao commented 4 years ago

最终如果Model的参数是传指针的话 那应该是只能用reflect.Value类型了

xenv commented 4 years ago

DataTypeOf(typ reflect.Type) string 是否更加简洁?

Type: d.DataTypeOf(p.Type)

DataTypeOf 应该不需要关心 Value 是什么。判断是不是 time.Time 似乎也可以使用:

if typ.ConvertibleTo(reflect.TypeOf(time.Time{})) {
    return "datetime"
}

@walkmiao 传不传指针不影响可读性吧?

walkmiao commented 4 years ago

Model()传指针有什么好处呢 我传的对象结构体也没有什么 这样做的好处在哪呢 仅仅是节约内存传指针的吗

ayuayue commented 4 years ago

var _ Dialect = (*sqlite3)(nil) 这种写法与go的版本有关系吗,写了以后编译器报错,执行也报错,说没有实现另一个方法

geektutu commented 4 years ago

@walkmiao Model 不修改原数据,所以传指针只是为了节省空间。而且对于复杂结构体来说,传结构体,也只是浅拷贝,意义也不大。

geektutu commented 4 years ago

@ayuayue 静态检查用的,参考 类似var _ PeerPicker = (*HTTPPool)(nil)这种设计目的是什么

wilgx0 commented 4 years ago

大佬不去培训机构当老师的话就太可惜了

BrianQy commented 3 years ago

table_test.go中的NewSession(),为什么不创建Engine实例就可以调用呢?我这边一直报红。

joewongex commented 2 years ago

@BrianQy table_test.go中的NewSession(),为什么不创建Engine实例就可以调用呢?我这边一直报红。

加入在raw_test.go中的两段代码就行了:

var (
    TestDB      *sql.DB
    TestDial, _ = dialect.GetDialect("sqlite3")
)

func TestMain(m *testing.M) {
    TestDB, _ = sql.Open("sqlite3", "../gee.db")
    code := m.Run()
    _ = TestDB.Close()
    os.Exit(code)
}

func NewSession() *Session {
    return New(TestDB, TestDial)
}
Alex-Jee commented 2 years ago

纠错:dialect 目录下新建文件 sqlite3.go时,应该在import里写上: "github.com/mattn/go-sqlite3" 来执行sqlite3的驱动的初始化,这样以后用到sqlite3时,只要导入dialect就自己执行了sqlite3的驱动的初始化,不用再写一遍import "github.com/mattn/go-sqlite3"(如果不写这个import就会使sql.Open失败)

sphierex commented 2 years ago

@Alex-Jee 纠错:dialect 目录下新建文件 sqlite3.go时,应该在import里写上: "github.com/mattn/go-sqlite3" 来执行sqlite3的驱动的初始化,这样以后用到sqlite3时,只要导入dialect就自己执行了sqlite3的驱动的初始化,不用再写一遍import "github.com/mattn/go-sqlite3"(如果不写这个import就会使sql.Open失败)

交给使用者调用会更明了些

niconical commented 2 years ago

请问Parse()函数中为什么不用reflect的Elem()函数而用Indirect()函数呢

ShiMaRing commented 2 years ago

@niconical 请问Parse()函数中为什么不用reflect的Elem()函数而用Indirect()函数呢

传入的类型为Interface,此时可以传入地址也可以传入结构体,如果采用Elem函数在对于传入结构体的情况下会发生Panic,而Indirect则可以正常执行

jfld commented 1 year ago

@niconical 请问Parse()函数中为什么不用reflect的Elem()函数而用Indirect()函数呢

Indirect返回v指向的值,如果v是个nil指针,Indirect返回0值,如果v不是指针,Indirect返回v本身。这里也理解了为啥要起Indirect这个名字,间接获取到了v指向的值. 这样可以兼容 结构体和指针的情况