docs update
Showing
8 changed files
with
280 additions
and
223 deletions
| ... | @@ -82,6 +82,8 @@ num, err := qs.Filter("User__Name", "slene").All(&posts) | ... | @@ -82,6 +82,8 @@ num, err := qs.Filter("User__Name", "slene").All(&posts) |
| 82 | 82 | ||
| 83 | #### Use Raw sql | 83 | #### Use Raw sql |
| 84 | 84 | ||
| 85 | If you don't like ORM,use Raw SQL to query / mapping without ORM setting | ||
| 86 | |||
| 85 | ```go | 87 | ```go |
| 86 | var maps []Params | 88 | var maps []Params |
| 87 | num, err := o.Raw("SELECT id FROM user WHERE name = ?", "slene").Values(&maps) | 89 | num, err := o.Raw("SELECT id FROM user WHERE name = ?", "slene").Values(&maps) | ... | ... |
| 1 | ## Model Definition | 1 | ## 模型定义 |
| 2 | 2 | ||
| 3 | 比较全面的 Model 定义例子,后文所有的例子如无特殊说明都以这个为基础。 | 3 | 复杂的模型定义不是必须的,此功能用作数据库数据转换和自动建表 |
| 4 | |||
| 5 | 当前还没有完成自动创建表的功能,所以提供一个 [Models.sql](Models.sql) 测试 | ||
| 6 | |||
| 7 | note: 根据文档的更新,随时都可能更新这个 Model | ||
| 8 | |||
| 9 | ##### models.go: | ||
| 10 | 4 | ||
| 11 | ```go | 5 | ## Struct Tag 设置参数 |
| 12 | package main | ||
| 13 | |||
| 14 | import ( | ||
| 15 | "github.com/astaxie/beego/orm" | ||
| 16 | "time" | ||
| 17 | ) | ||
| 18 | |||
| 19 | type User struct { | ||
| 20 | Id int `orm:"auto"` // 设置为auto主键 | ||
| 21 | UserName string `orm:"size(30);unique"` // 设置字段为unique | ||
| 22 | Email string `orm:"size(100)"` // 设置string字段长度时,会使用varchar类型 | ||
| 23 | Password string `orm:"size(100)"` | ||
| 24 | Status int16 `orm:"choices(0,1,2,3);defalut(0)"` // choices设置可选值 | ||
| 25 | IsStaff bool `orm:"default(false)"` // default设置默认值 | ||
| 26 | IsActive bool `orm:"default(0)"` | ||
| 27 | Created time.Time `orm:"auto_now_add;type(date)"` // 创建时自动设置时间 | ||
| 28 | Updated time.Time `orm:"auto_now"` // 每次更新时自动设置时间 | ||
| 29 | Profile *Profile `orm:"null;rel(one);on_delete(set_null)"` // OneToOne relation, 级联删除时设置为NULL | ||
| 30 | Posts []*Post `orm:"reverse(many)" json:"-"` // fk 的反向关系 | ||
| 31 | orm.Manager `json:"-"` // 每个model都需要定义orm.Manager | ||
| 32 | } | ||
| 33 | |||
| 34 | // 定义NewModel进行orm.Manager的初始化(必须) | ||
| 35 | func NewUser() *User { | ||
| 36 | obj := new(User) | ||
| 37 | obj.Manager.Init(obj) | ||
| 38 | return obj | ||
| 39 | } | ||
| 40 | |||
| 41 | type Profile struct { | ||
| 42 | Id int `orm:"auto"` | ||
| 43 | Age int16 `` | ||
| 44 | Money float64 `` | ||
| 45 | User *User `orm:"reverse(one)" json:"-"` // 设置反向关系(字段可选) | ||
| 46 | orm.Manager `json:"-"` | ||
| 47 | } | ||
| 48 | |||
| 49 | func (u *Profile) TableName() string { | ||
| 50 | return "profile" // 自定义表名 | ||
| 51 | } | ||
| 52 | |||
| 53 | func NewProfile() *Profile { | ||
| 54 | obj := new(Profile) | ||
| 55 | obj.Manager.Init(obj) | ||
| 56 | return obj | ||
| 57 | } | ||
| 58 | |||
| 59 | type Post struct { | ||
| 60 | Id int `orm:"auto"` | ||
| 61 | User *User `orm:"rel(fk)"` // RelForeignKey relation | ||
| 62 | Title string `orm:"size(60)"` | ||
| 63 | Content string `` | ||
| 64 | Created time.Time `` | ||
| 65 | Updated time.Time `` | ||
| 66 | Tags []*Tag `orm:"rel(m2m)"` // ManyToMany relation | ||
| 67 | orm.Manager `json:"-"` | ||
| 68 | } | ||
| 69 | |||
| 70 | func NewPost() *Post { | ||
| 71 | obj := new(Post) | ||
| 72 | obj.Manager.Init(obj) | ||
| 73 | return obj | ||
| 74 | } | ||
| 75 | |||
| 76 | type Tag struct { | ||
| 77 | Id int `orm:"auto"` | ||
| 78 | Name string `orm:"size(30)"` | ||
| 79 | Status int16 `orm:"choices(0,1,2);default(0)"` | ||
| 80 | Posts []*Post `orm:"reverse(many)" json:"-"` | ||
| 81 | orm.Manager `json:"-"` | ||
| 82 | } | ||
| 83 | |||
| 84 | func NewTag() *Tag { | ||
| 85 | obj := new(Tag) | ||
| 86 | obj.Manager.Init(obj) | ||
| 87 | return obj | ||
| 88 | } | ||
| 89 | |||
| 90 | type Comment struct { | ||
| 91 | Id int `orm:"auto"` | ||
| 92 | Post *Post `orm:"rel(fk)"` | ||
| 93 | Content string `` | ||
| 94 | Parent *Comment `orm:"null;rel(fk)"` // null设置allow NULL | ||
| 95 | Status int16 `orm:"choices(0,1,2);default(0)"` | ||
| 96 | Created time.Time `orm:"auto_now_add"` | ||
| 97 | orm.Manager `json:"-"` | ||
| 98 | } | ||
| 99 | |||
| 100 | func NewComment() *Comment { | ||
| 101 | obj := new(Comment) | ||
| 102 | obj.Manager.Init(obj) | ||
| 103 | return obj | ||
| 104 | } | ||
| 105 | |||
| 106 | func init() { | ||
| 107 | // 需要在init中注册定义的model | ||
| 108 | orm.RegisterModel(new(User), new(Profile)) | ||
| 109 | orm.RegisterModel(new(Post), new(Tag), new(Comment)) | ||
| 110 | } | ||
| 111 | ``` | ||
| 112 | |||
| 113 | ## Field Type | ||
| 114 | |||
| 115 | 现在 orm 支持下面的字段形式 | ||
| 116 | |||
| 117 | | go type | field type | mysql type | ||
| 118 | | :--- | :--- | :--- | ||
| 119 | | bool | TypeBooleanField | tinyint | ||
| 120 | | string | TypeCharField | varchar | ||
| 121 | | string | TypeTextField | longtext | ||
| 122 | | time.Time | TypeDateField | date | ||
| 123 | | time.TIme | TypeDateTimeField | datetime | ||
| 124 | | int16 |TypeSmallIntegerField | int(4) | ||
| 125 | | int, int32 |TypeIntegerField | int(11) | ||
| 126 | | int64 |TypeBigIntegerField | bigint(20) | ||
| 127 | | uint, uint16 |TypePositiveSmallIntegerField | int(4) unsigned | ||
| 128 | | uint32 |TypePositiveIntegerField | int(11) unsigned | ||
| 129 | | uint64 |TypePositiveBigIntegerField | bigint(20) unsigned | ||
| 130 | | float32, float64 | TypeFloatField | double | ||
| 131 | | float32, float64 | TypeDecimalField | double(digits, decimals) | ||
| 132 | |||
| 133 | 关系型的字段,其字段类型取决于对应的主键。 | ||
| 134 | |||
| 135 | * RelForeignKey | ||
| 136 | * RelOneToOne | ||
| 137 | * RelManyToMany | ||
| 138 | * RelReverseOne | ||
| 139 | * RelReverseMany | ||
| 140 | |||
| 141 | ## Field Options | ||
| 142 | ```go | 6 | ```go |
| 143 | orm:"null;rel(fk)" | 7 | orm:"null;rel(fk)" |
| 144 | ``` | 8 | ``` |
| ... | @@ -175,13 +39,26 @@ orm:"null;rel(fk)" | ... | @@ -175,13 +39,26 @@ orm:"null;rel(fk)" |
| 175 | 39 | ||
| 176 | 为字段设置 db 字段的名称 | 40 | 为字段设置 db 字段的名称 |
| 177 | ```go | 41 | ```go |
| 178 | UserName `orm:"column(db_user_name)"` | 42 | Name `orm:"column(user_name)"` |
| 179 | ``` | 43 | ``` |
| 180 | #### default | 44 | #### default |
| 181 | 45 | ||
| 182 | 为字段设置默认值,类型必须符合 | 46 | 为字段设置默认值,类型必须符合 |
| 183 | ```go | 47 | ```go |
| 184 | Status int `orm:"default(1)"` | 48 | type User struct { |
| 49 | ... | ||
| 50 | Status int `orm:"default(1)"` | ||
| 51 | ``` | ||
| 52 | 仅当进行 orm.Manager 初始化时才会赋值 | ||
| 53 | ```go | ||
| 54 | func NewUser() *User { | ||
| 55 | obj := new(User) | ||
| 56 | obj.Manager.Init(obj) | ||
| 57 | return obj | ||
| 58 | } | ||
| 59 | |||
| 60 | u := NewUser() | ||
| 61 | fmt.Println(u.Status) // 1 | ||
| 185 | ``` | 62 | ``` |
| 186 | #### choices | 63 | #### choices |
| 187 | 64 | ||
| ... | @@ -219,7 +96,7 @@ Updated time.Time `auto_now` | ... | @@ -219,7 +96,7 @@ Updated time.Time `auto_now` |
| 219 | ```go | 96 | ```go |
| 220 | Created time.Time `orm:"auto_now_add;type(date)"` | 97 | Created time.Time `orm:"auto_now_add;type(date)"` |
| 221 | ``` | 98 | ``` |
| 222 | ## Relation Field Options | 99 | ## 表关系设置 |
| 223 | 100 | ||
| 224 | #### rel / reverse | 101 | #### rel / reverse |
| 225 | 102 | ||
| ... | @@ -291,3 +168,32 @@ type Profile struct { | ... | @@ -291,3 +168,32 @@ type Profile struct { |
| 291 | 168 | ||
| 292 | // 删除 Profile 时将设置 User.Profile 的数据库字段为 NULL | 169 | // 删除 Profile 时将设置 User.Profile 的数据库字段为 NULL |
| 293 | ``` | 170 | ``` |
| 171 | |||
| 172 | |||
| 173 | ## Struct Field 类型与数据库的对应 | ||
| 174 | |||
| 175 | 现在 orm 支持下面的字段形式 | ||
| 176 | |||
| 177 | | go type | field type | mysql type | ||
| 178 | | :--- | :--- | :--- | ||
| 179 | | bool | TypeBooleanField | tinyint | ||
| 180 | | string | TypeCharField | varchar | ||
| 181 | | string | TypeTextField | longtext | ||
| 182 | | time.Time | TypeDateField | date | ||
| 183 | | time.TIme | TypeDateTimeField | datetime | ||
| 184 | | int16 |TypeSmallIntegerField | int(4) | ||
| 185 | | int, int32 |TypeIntegerField | int(11) | ||
| 186 | | int64 |TypeBigIntegerField | bigint(20) | ||
| 187 | | uint, uint16 |TypePositiveSmallIntegerField | int(4) unsigned | ||
| 188 | | uint32 |TypePositiveIntegerField | int(11) unsigned | ||
| 189 | | uint64 |TypePositiveBigIntegerField | bigint(20) unsigned | ||
| 190 | | float32, float64 | TypeFloatField | double | ||
| 191 | | float32, float64 | TypeDecimalField | double(digits, decimals) | ||
| 192 | |||
| 193 | 关系型的字段,其字段类型取决于对应的主键。 | ||
| 194 | |||
| 195 | * RelForeignKey | ||
| 196 | * RelOneToOne | ||
| 197 | * RelManyToMany | ||
| 198 | * RelReverseOne | ||
| 199 | * RelReverseMany | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
| 1 | ## Object | 1 | ## 对象的CRUD操作 |
| 2 | 2 | ||
| 3 | 对 object 操作简单的三个方法 Read / Insert / Update / Delete | 3 | 对 object 操作简单的三个方法 Read / Insert / Update / Delete |
| 4 | ```go | 4 | ```go |
| 5 | o := orm.NewOrm() | 5 | o := orm.NewOrm() |
| 6 | user := NewUser() | 6 | user := NewUser() |
| 7 | user.UserName = "slene" | 7 | user.Name = "slene" |
| 8 | user.Password = "password" | ||
| 9 | user.Email = "vslene@gmail.com" | ||
| 10 | 8 | ||
| 11 | fmt.Println(o.Insert(user)) | 9 | fmt.Println(o.Insert(user)) |
| 12 | 10 | ||
| 13 | user.UserName = "Your" | 11 | user.Name = "Your" |
| 14 | fmt.Println(o.Update(user)) | 12 | fmt.Println(o.Update(user)) |
| 15 | fmt.Println(o.Read(user)) | 13 | fmt.Println(o.Read(user)) |
| 16 | fmt.Println(o.Delete(user)) | 14 | fmt.Println(o.Delete(user)) |
| ... | @@ -27,16 +25,14 @@ if err == sql.ErrNoRows { | ... | @@ -27,16 +25,14 @@ if err == sql.ErrNoRows { |
| 27 | } else if err == orm.ErrMissPK { | 25 | } else if err == orm.ErrMissPK { |
| 28 | fmt.Println("找不到主键") | 26 | fmt.Println("找不到主键") |
| 29 | } else { | 27 | } else { |
| 30 | fmt.Println(user.Id, user.UserName) | 28 | fmt.Println(user.Id, user.Name) |
| 31 | } | 29 | } |
| 32 | ``` | 30 | ``` |
| 33 | ### Insert | 31 | ### Insert |
| 34 | ```go | 32 | ```go |
| 35 | o := orm.NewOrm() | 33 | o := orm.NewOrm() |
| 36 | var user User | 34 | var user User |
| 37 | user.UserName = "slene" | 35 | user.Name = "slene" |
| 38 | user.Password = "password" | ||
| 39 | user.Email = "vslene@gmail.com"[]() | ||
| 40 | user.IsActive = true | 36 | user.IsActive = true |
| 41 | 37 | ||
| 42 | fmt.Println(o.Insert(&user)) | 38 | fmt.Println(o.Insert(&user)) |
| ... | @@ -49,7 +45,7 @@ fmt.Println(user.Id) | ... | @@ -49,7 +45,7 @@ fmt.Println(user.Id) |
| 49 | o := orm.NewOrm() | 45 | o := orm.NewOrm() |
| 50 | user := User{Id: 1} | 46 | user := User{Id: 1} |
| 51 | if o.Read(&user) == nil { | 47 | if o.Read(&user) == nil { |
| 52 | user.UserName = "MyName" | 48 | user.Name = "MyName" |
| 53 | o.Update(&user) | 49 | o.Update(&user) |
| 54 | } | 50 | } |
| 55 | ``` | 51 | ``` | ... | ... |
| 1 | ## Orm | 1 | ## Orm 使用方法 |
| 2 | 2 | ||
| 3 | beego/orm 的使用例子 | 3 | beego/orm 的使用例子 |
| 4 | |||
| 5 | 后文例子如无特殊说明都以这个为基础。 | ||
| 6 | |||
| 7 | ##### models.go: | ||
| 8 | |||
| 9 | ```go | ||
| 10 | package main | ||
| 11 | |||
| 12 | import ( | ||
| 13 | "github.com/astaxie/beego/orm" | ||
| 14 | ) | ||
| 15 | |||
| 16 | type User struct { | ||
| 17 | Id int `orm:"auto"` // 设置为auto主键 | ||
| 18 | Name string | ||
| 19 | Profile *Profile `orm:"rel(one)"` // OneToOne relation | ||
| 20 | orm.Manager // 每个model都需要定义orm.Manager | ||
| 21 | } | ||
| 22 | |||
| 23 | type Profile struct { | ||
| 24 | Id int `orm:"auto"` | ||
| 25 | Age int16 | ||
| 26 | User *User `orm:"reverse(one)"` // 设置反向关系(可选) | ||
| 27 | orm.Manager | ||
| 28 | } | ||
| 29 | |||
| 30 | func init() { | ||
| 31 | // 需要在init中注册定义的model | ||
| 32 | orm.RegisterModel(new(User), new(Profile)) | ||
| 33 | } | ||
| 34 | ``` | ||
| 35 | |||
| 36 | ##### main.go | ||
| 37 | |||
| 4 | ```go | 38 | ```go |
| 5 | package main | 39 | package main |
| 6 | 40 | ||
| ... | @@ -22,20 +56,18 @@ func main() { | ... | @@ -22,20 +56,18 @@ func main() { |
| 22 | 56 | ||
| 23 | profile := NewProfile() | 57 | profile := NewProfile() |
| 24 | profile.Age = 30 | 58 | profile.Age = 30 |
| 25 | profile.Money = 9.8 | ||
| 26 | 59 | ||
| 27 | user := NewUser() | 60 | user := NewUser() |
| 28 | user.Profile = profile | 61 | user.Profile = profile |
| 29 | user.UserName = "slene" | 62 | user.Name = "slene" |
| 30 | user.Password = "password" | ||
| 31 | user.Email = "vslene@gmail.com" | ||
| 32 | user.IsActive = true | ||
| 33 | 63 | ||
| 34 | fmt.Println(o.Insert(profile)) | 64 | fmt.Println(o.Insert(profile)) |
| 35 | fmt.Println(o.Insert(user)) | 65 | fmt.Println(o.Insert(user)) |
| 36 | } | 66 | } |
| 37 | ``` | 67 | ``` |
| 38 | 68 | ||
| 69 | ## 数据库的设置 | ||
| 70 | |||
| 39 | #### RegisterDriver | 71 | #### RegisterDriver |
| 40 | 72 | ||
| 41 | 三种数据库类型 | 73 | 三种数据库类型 |
| ... | @@ -66,12 +98,14 @@ orm 必须注册一个名称为 `default` 的数据库,用以作为默认使 | ... | @@ -66,12 +98,14 @@ orm 必须注册一个名称为 `default` 的数据库,用以作为默认使 |
| 66 | orm.RegisterDataBase("default", "mysql", "root:root@/orm_test?charset=utf8", 30) | 98 | orm.RegisterDataBase("default", "mysql", "root:root@/orm_test?charset=utf8", 30) |
| 67 | ``` | 99 | ``` |
| 68 | 100 | ||
| 69 | ## Ormer | 101 | ## ORM 接口使用 |
| 102 | |||
| 103 | 使用 orm 必然接触的 Ormer 接口,我们来熟悉一下 | ||
| 70 | 104 | ||
| 71 | ```go | 105 | ```go |
| 72 | var o Ormer | 106 | var o Ormer |
| 73 | o = orm.NewOrm() // 创建一个 Ormer | 107 | o = orm.NewOrm() // 创建一个 Ormer |
| 74 | // NewOrm 的同时会执行一次 orm.BootStrap,用以验证模型之间的定义并缓存。 | 108 | // NewOrm 的同时会执行 orm.BootStrap (整个 app 只执行一次),用以验证模型之间的定义并缓存。 |
| 75 | ``` | 109 | ``` |
| 76 | 110 | ||
| 77 | * type Ormer interface { | 111 | * type Ormer interface { |
| ... | @@ -84,9 +118,9 @@ o = orm.NewOrm() // 创建一个 Ormer | ... | @@ -84,9 +118,9 @@ o = orm.NewOrm() // 创建一个 Ormer |
| 84 | * [LoadRel(Modeler, string) (int64, error)](Object.md#loadRel) | 118 | * [LoadRel(Modeler, string) (int64, error)](Object.md#loadRel) |
| 85 | * [QueryTable(interface{}) QuerySeter](#querytable) | 119 | * [QueryTable(interface{}) QuerySeter](#querytable) |
| 86 | * [Using(string) error](#using) | 120 | * [Using(string) error](#using) |
| 87 | * [Begin() error](Transaction.md#begin) | 121 | * [Begin() error](Transaction.md) |
| 88 | * [Commit() error](Transaction.md#commit) | 122 | * [Commit() error](Transaction.md) |
| 89 | * [Rollback() error](Transaction.md#rollback) | 123 | * [Rollback() error](Transaction.md) |
| 90 | * [Raw(string, ...interface{}) RawSeter](#raw) | 124 | * [Raw(string, ...interface{}) RawSeter](#raw) |
| 91 | * [Driver() Driver](#driver) | 125 | * [Driver() Driver](#driver) |
| 92 | * } | 126 | * } |
| ... | @@ -133,7 +167,7 @@ Raw 函数,返回一个 [RawSeter](Raw.md) 用以对设置的 sql 语句和参 | ... | @@ -133,7 +167,7 @@ Raw 函数,返回一个 [RawSeter](Raw.md) 用以对设置的 sql 语句和参 |
| 133 | ```go | 167 | ```go |
| 134 | o := NewOrm() | 168 | o := NewOrm() |
| 135 | var r RawSeter | 169 | var r RawSeter |
| 136 | r = o.Raw("UPDATE user SET user_name = ? WHERE user_name = ?", "testing", "slene") | 170 | r = o.Raw("UPDATE user SET name = ? WHERE name = ?", "testing", "slene") |
| 137 | ``` | 171 | ``` |
| 138 | 172 | ||
| 139 | #### Driver | 173 | #### Driver | ... | ... |
| 1 | ## Query | 1 | ## 高级查询 |
| 2 | 2 | ||
| 3 | orm 以 **QuerySeter** 来组织查询,每个返回 **QuerySeter** 的方法都会获得一个新的 **QuerySeter** 对象。 | 3 | orm 以 **QuerySeter** 来组织查询,每个返回 **QuerySeter** 的方法都会获得一个新的 **QuerySeter** 对象。 |
| 4 | 4 | ||
| ... | @@ -29,8 +29,8 @@ qs.Filter("profile__age__gt", 18) // WHERE profile.age > 18 | ... | @@ -29,8 +29,8 @@ qs.Filter("profile__age__gt", 18) // WHERE profile.age > 18 |
| 29 | qs.Filter("profile__age__gte", 18) // WHERE profile.age >= 18 | 29 | qs.Filter("profile__age__gte", 18) // WHERE profile.age >= 18 |
| 30 | qs.Filter("profile__age__in", 18, 20) // WHERE profile.age IN (18, 20) | 30 | qs.Filter("profile__age__in", 18, 20) // WHERE profile.age IN (18, 20) |
| 31 | 31 | ||
| 32 | qs.Filter("profile__age__in", 18, 20).Exclude("profile__money__lt", 1000) | 32 | qs.Filter("profile__age__in", 18, 20).Exclude("profile__lt", 1000) |
| 33 | // WHERE profile.age IN (18, 20) AND NOT profile.money < 1000 | 33 | // WHERE profile.age IN (18, 20) AND NOT profile_id < 1000 |
| 34 | ``` | 34 | ``` |
| 35 | ## Operators | 35 | ## Operators |
| 36 | 36 | ||
| ... | @@ -51,27 +51,27 @@ qs.Filter("profile__age__in", 18, 20).Exclude("profile__money__lt", 1000) | ... | @@ -51,27 +51,27 @@ qs.Filter("profile__age__in", 18, 20).Exclude("profile__money__lt", 1000) |
| 51 | 51 | ||
| 52 | Filter / Exclude / Condition expr 的默认值 | 52 | Filter / Exclude / Condition expr 的默认值 |
| 53 | ```go | 53 | ```go |
| 54 | qs.Filter("user_name", "slene") // WHERE user_name = 'slene' | 54 | qs.Filter("name", "slene") // WHERE name = 'slene' |
| 55 | qs.Filter("user_name__exact", "slene") // WHERE user_name = 'slene' | 55 | qs.Filter("name__exact", "slene") // WHERE name = 'slene' |
| 56 | // 使用 = 匹配,大小写是否敏感取决于数据表使用的 collation | 56 | // 使用 = 匹配,大小写是否敏感取决于数据表使用的 collation |
| 57 | qs.Filter("profile", nil) // WHERE profile_id IS NULL | 57 | qs.Filter("profile", nil) // WHERE profile_id IS NULL |
| 58 | ``` | 58 | ``` |
| 59 | #### iexact | 59 | #### iexact |
| 60 | ```go | 60 | ```go |
| 61 | qs.Filter("user_name__iexact", "slene") | 61 | qs.Filter("name__iexact", "slene") |
| 62 | // WHERE user_name LIKE 'slene' | 62 | // WHERE name LIKE 'slene' |
| 63 | // 大小写不敏感,匹配任意 'Slene' 'sLENE' | 63 | // 大小写不敏感,匹配任意 'Slene' 'sLENE' |
| 64 | ``` | 64 | ``` |
| 65 | #### contains | 65 | #### contains |
| 66 | ```go | 66 | ```go |
| 67 | qs.Filter("user_name__contains", "slene") | 67 | qs.Filter("name__contains", "slene") |
| 68 | // WHERE user_name LIKE BINARY '%slene%' | 68 | // WHERE name LIKE BINARY '%slene%' |
| 69 | // 大小写敏感, 匹配包含 slene 的字符 | 69 | // 大小写敏感, 匹配包含 slene 的字符 |
| 70 | ``` | 70 | ``` |
| 71 | #### icontains | 71 | #### icontains |
| 72 | ```go | 72 | ```go |
| 73 | qs.Filter("user_name__icontains", "slene") | 73 | qs.Filter("name__icontains", "slene") |
| 74 | // WHERE user_name LIKE '%slene%' | 74 | // WHERE name LIKE '%slene%' |
| 75 | // 大小写不敏感, 匹配任意 'im Slene', 'im sLENE' | 75 | // 大小写不敏感, 匹配任意 'im Slene', 'im sLENE' |
| 76 | ``` | 76 | ``` |
| 77 | #### in | 77 | #### in |
| ... | @@ -97,26 +97,26 @@ qs.Filter("profile__age__lte", 18) | ... | @@ -97,26 +97,26 @@ qs.Filter("profile__age__lte", 18) |
| 97 | ``` | 97 | ``` |
| 98 | #### startswith | 98 | #### startswith |
| 99 | ```go | 99 | ```go |
| 100 | qs.Filter("user_name__startswith", "slene") | 100 | qs.Filter("name__startswith", "slene") |
| 101 | // WHERE user_name LIKE BINARY 'slene%' | 101 | // WHERE name LIKE BINARY 'slene%' |
| 102 | // 大小写敏感, 匹配以 'slene' 起始的字符串 | 102 | // 大小写敏感, 匹配以 'slene' 起始的字符串 |
| 103 | ``` | 103 | ``` |
| 104 | #### istartswith | 104 | #### istartswith |
| 105 | ```go | 105 | ```go |
| 106 | qs.Filter("user_name__istartswith", "slene") | 106 | qs.Filter("name__istartswith", "slene") |
| 107 | // WHERE user_name LIKE 'slene%' | 107 | // WHERE name LIKE 'slene%' |
| 108 | // 大小写不敏感, 匹配任意以 'slene', 'Slene' 起始的字符串 | 108 | // 大小写不敏感, 匹配任意以 'slene', 'Slene' 起始的字符串 |
| 109 | ``` | 109 | ``` |
| 110 | #### endswith | 110 | #### endswith |
| 111 | ```go | 111 | ```go |
| 112 | qs.Filter("user_name__endswith", "slene") | 112 | qs.Filter("name__endswith", "slene") |
| 113 | // WHERE user_name LIKE BINARY '%slene' | 113 | // WHERE name LIKE BINARY '%slene' |
| 114 | // 大小写敏感, 匹配以 'slene' 结束的字符串 | 114 | // 大小写敏感, 匹配以 'slene' 结束的字符串 |
| 115 | ``` | 115 | ``` |
| 116 | #### iendswith | 116 | #### iendswith |
| 117 | ```go | 117 | ```go |
| 118 | qs.Filter("user_name__startswith", "slene") | 118 | qs.Filter("name__startswith", "slene") |
| 119 | // WHERE user_name LIKE '%slene' | 119 | // WHERE name LIKE '%slene' |
| 120 | // 大小写不敏感, 匹配任意以 'slene', 'Slene' 结束的字符串 | 120 | // 大小写不敏感, 匹配任意以 'slene', 'Slene' 结束的字符串 |
| 121 | ``` | 121 | ``` |
| 122 | #### isnull | 122 | #### isnull |
| ... | @@ -128,9 +128,9 @@ qs.Filter("profile_id__isnull", true) | ... | @@ -128,9 +128,9 @@ qs.Filter("profile_id__isnull", true) |
| 128 | qs.Filter("profile__isnull", false) | 128 | qs.Filter("profile__isnull", false) |
| 129 | // WHERE profile_id IS NOT NULL | 129 | // WHERE profile_id IS NOT NULL |
| 130 | ``` | 130 | ``` |
| 131 | ## QuerySeter | 131 | ## 高级查询接口使用 |
| 132 | 132 | ||
| 133 | QuerySeter 当前支持的方法 | 133 | QuerySeter 是高级查询使用的接口,我们来熟悉下他的接口方法 |
| 134 | 134 | ||
| 135 | * type QuerySeter interface { | 135 | * type QuerySeter interface { |
| 136 | * [Filter(string, ...interface{}) QuerySeter](#filter) | 136 | * [Filter(string, ...interface{}) QuerySeter](#filter) |
| ... | @@ -151,24 +151,30 @@ QuerySeter 当前支持的方法 | ... | @@ -151,24 +151,30 @@ QuerySeter 当前支持的方法 |
| 151 | * [ValuesFlat(*ParamsList, string) (int64, error)](#valuesflat) | 151 | * [ValuesFlat(*ParamsList, string) (int64, error)](#valuesflat) |
| 152 | * } | 152 | * } |
| 153 | 153 | ||
| 154 | 每个返回 QuerySeter 的 api 调用时都会新建一个 QuerySeter,不影响之前创建的。 | 154 | * 每个返回 QuerySeter 的 api 调用时都会新建一个 QuerySeter,不影响之前创建的。 |
| 155 | |||
| 156 | * 高级查询使用 Filter 和 Exclude 来做常用的条件查询。囊括两种清晰的过滤规则:包含, 排除 | ||
| 155 | 157 | ||
| 156 | #### Filter | 158 | #### Filter |
| 157 | 159 | ||
| 160 | 用来过滤查询结果,起到 **包含条件** 的作用 | ||
| 161 | |||
| 158 | 多个 Filter 之间使用 `AND` 连接 | 162 | 多个 Filter 之间使用 `AND` 连接 |
| 159 | ```go | 163 | ```go |
| 160 | qs.Filter("profile__isnull", true).Filter("user_name", "slene") | 164 | qs.Filter("profile__isnull", true).Filter("name", "slene") |
| 161 | // WHERE profile_id IS NULL AND user_name = 'slene' | 165 | // WHERE profile_id IS NULL AND name = 'slene' |
| 162 | ``` | 166 | ``` |
| 163 | 167 | ||
| 164 | #### Exclude | 168 | #### Exclude |
| 165 | 169 | ||
| 170 | 用来过滤查询结果,起到 **排除条件** 的作用 | ||
| 171 | |||
| 166 | 使用 `NOT` 排除条件 | 172 | 使用 `NOT` 排除条件 |
| 167 | 173 | ||
| 168 | 多个 Exclude 之间使用 `AND` 连接 | 174 | 多个 Exclude 之间使用 `AND` 连接 |
| 169 | ```go | 175 | ```go |
| 170 | qs.Exclude("profile__isnull", true).Filter("user_name", "slene") | 176 | qs.Exclude("profile__isnull", true).Filter("name", "slene") |
| 171 | // WHERE NOT profile_id IS NULL AND user_name = 'slene' | 177 | // WHERE NOT profile_id IS NULL AND name = 'slene' |
| 172 | ``` | 178 | ``` |
| 173 | 179 | ||
| 174 | #### SetCond | 180 | #### SetCond |
| ... | @@ -183,7 +189,7 @@ qs := orm.QueryTable("user") | ... | @@ -183,7 +189,7 @@ qs := orm.QueryTable("user") |
| 183 | qs = qs.SetCond(cond1) | 189 | qs = qs.SetCond(cond1) |
| 184 | // WHERE ... AND ... AND NOT ... OR ... | 190 | // WHERE ... AND ... AND NOT ... OR ... |
| 185 | 191 | ||
| 186 | cond2 := cond.AndCond(cond1).OrCond(cond.And("user_name", "slene")) | 192 | cond2 := cond.AndCond(cond1).OrCond(cond.And("name", "slene")) |
| 187 | qs = qs.SetCond(cond2).Count() | 193 | qs = qs.SetCond(cond2).Count() |
| 188 | // WHERE (... AND ... AND NOT ... OR ...) OR ( ... ) | 194 | // WHERE (... AND ... AND NOT ... OR ...) OR ( ... ) |
| 189 | ``` | 195 | ``` |
| ... | @@ -228,8 +234,8 @@ qs.Offset(20) | ... | @@ -228,8 +234,8 @@ qs.Offset(20) |
| 228 | qs.OrderBy("id", "-profile__age") | 234 | qs.OrderBy("id", "-profile__age") |
| 229 | // ORDER BY id ASC, profile.age DESC | 235 | // ORDER BY id ASC, profile.age DESC |
| 230 | 236 | ||
| 231 | qs.OrderBy("-profile__money", "profile") | 237 | qs.OrderBy("-profile__age", "profile") |
| 232 | // ORDER BY profile.money DESC, profile_id ASC | 238 | // ORDER BY profile.age DESC, profile_id ASC |
| 233 | ``` | 239 | ``` |
| 234 | 240 | ||
| 235 | #### RelatedSel | 241 | #### RelatedSel |
| ... | @@ -260,19 +266,19 @@ fmt.Printf("Count Num: %s, %s", cnt, err) | ... | @@ -260,19 +266,19 @@ fmt.Printf("Count Num: %s, %s", cnt, err) |
| 260 | #### Update | 266 | #### Update |
| 261 | 依据当前查询条件,进行批量更新操作 | 267 | 依据当前查询条件,进行批量更新操作 |
| 262 | ```go | 268 | ```go |
| 263 | num, err := o.QueryTable("user").Filter("user_name", "slene").Update(orm.Params{ | 269 | num, err := o.QueryTable("user").Filter("name", "slene").Update(orm.Params{ |
| 264 | "user_name": "astaxie", | 270 | "name": "astaxie", |
| 265 | }) | 271 | }) |
| 266 | fmt.Printf("Affected Num: %s, %s", num, err) | 272 | fmt.Printf("Affected Num: %s, %s", num, err) |
| 267 | // SET user_name = "astaixe" WHERE user_name = "slene" | 273 | // SET name = "astaixe" WHERE name = "slene" |
| 268 | ``` | 274 | ``` |
| 269 | 275 | ||
| 270 | #### Delete | 276 | #### Delete |
| 271 | 依据当前查询条件,进行批量删除操作 | 277 | 依据当前查询条件,进行批量删除操作 |
| 272 | ```go | 278 | ```go |
| 273 | num, err := o.QueryTable("user").Filter("user_name", "slene").Delete() | 279 | num, err := o.QueryTable("user").Filter("name", "slene").Delete() |
| 274 | fmt.Printf("Affected Num: %s, %s", num, err) | 280 | fmt.Printf("Affected Num: %s, %s", num, err) |
| 275 | // DELETE FROM user WHERE user_name = "slene" | 281 | // DELETE FROM user WHERE name = "slene" |
| 276 | ``` | 282 | ``` |
| 277 | 283 | ||
| 278 | #### PrepareInsert | 284 | #### PrepareInsert |
| ... | @@ -282,7 +288,7 @@ fmt.Printf("Affected Num: %s, %s", num, err) | ... | @@ -282,7 +288,7 @@ fmt.Printf("Affected Num: %s, %s", num, err) |
| 282 | ```go | 288 | ```go |
| 283 | var users []*User | 289 | var users []*User |
| 284 | ... | 290 | ... |
| 285 | qs := dORM.QueryTable("user") | 291 | qs := o.QueryTable("user") |
| 286 | i, _ := qs.PrepareInsert() | 292 | i, _ := qs.PrepareInsert() |
| 287 | for _, user := range users { | 293 | for _, user := range users { |
| 288 | id, err := i.Insert(user) | 294 | id, err := i.Insert(user) |
| ... | @@ -290,8 +296,8 @@ for _, user := range users { | ... | @@ -290,8 +296,8 @@ for _, user := range users { |
| 290 | ... | 296 | ... |
| 291 | } | 297 | } |
| 292 | } | 298 | } |
| 293 | // PREPARE INSERT INTO user (`user_name`, ...) VALUES (?, ...) | 299 | // PREPARE INSERT INTO user (`name`, ...) VALUES (?, ...) |
| 294 | // EXECUTE INSERT INTO user (`user_name`, ...) VALUES ("slene", ...) | 300 | // EXECUTE INSERT INTO user (`name`, ...) VALUES ("slene", ...) |
| 295 | // EXECUTE ... | 301 | // EXECUTE ... |
| 296 | // ... | 302 | // ... |
| 297 | i.Close() // 别忘记关闭 statement | 303 | i.Close() // 别忘记关闭 statement |
| ... | @@ -301,7 +307,7 @@ i.Close() // 别忘记关闭 statement | ... | @@ -301,7 +307,7 @@ i.Close() // 别忘记关闭 statement |
| 301 | 返回对应的结果集对象 | 307 | 返回对应的结果集对象 |
| 302 | ```go | 308 | ```go |
| 303 | var users []*User | 309 | var users []*User |
| 304 | num, err := o.QueryTable("user").Filter("user_name", "slene").All(&users) | 310 | num, err := o.QueryTable("user").Filter("name", "slene").All(&users) |
| 305 | fmt.Printf("Returned Rows Num: %s, %s", num, err) | 311 | fmt.Printf("Returned Rows Num: %s, %s", num, err) |
| 306 | ``` | 312 | ``` |
| 307 | 313 | ||
| ... | @@ -311,7 +317,7 @@ fmt.Printf("Returned Rows Num: %s, %s", num, err) | ... | @@ -311,7 +317,7 @@ fmt.Printf("Returned Rows Num: %s, %s", num, err) |
| 311 | 317 | ||
| 312 | ```go | 318 | ```go |
| 313 | var user *User | 319 | var user *User |
| 314 | err := o.QueryTable("user").Filter("user_name", "slene").One(&user) | 320 | err := o.QueryTable("user").Filter("name", "slene").One(&user) |
| 315 | if err == orm.ErrMultiRows { | 321 | if err == orm.ErrMultiRows { |
| 316 | // 多条的时候报错 | 322 | // 多条的时候报错 |
| 317 | fmt.Printf("Returned Multi Rows Not One") | 323 | fmt.Printf("Returned Multi Rows Not One") |
| ... | @@ -333,7 +339,7 @@ num, err := o.QueryTable("user").Values(&maps) | ... | @@ -333,7 +339,7 @@ num, err := o.QueryTable("user").Values(&maps) |
| 333 | if err != nil { | 339 | if err != nil { |
| 334 | fmt.Printf("Result Nums: %d\n", num) | 340 | fmt.Printf("Result Nums: %d\n", num) |
| 335 | for _, m := range maps { | 341 | for _, m := range maps { |
| 336 | fmt.Println(m["Id"], m["UserName"]) | 342 | fmt.Println(m["Id"], m["Name"]) |
| 337 | } | 343 | } |
| 338 | } | 344 | } |
| 339 | ``` | 345 | ``` |
| ... | @@ -346,11 +352,11 @@ if err != nil { | ... | @@ -346,11 +352,11 @@ if err != nil { |
| 346 | 352 | ||
| 347 | ```go | 353 | ```go |
| 348 | var maps []orm.Params | 354 | var maps []orm.Params |
| 349 | num, err := o.QueryTable("user").Values(&maps, "id", "user_name", "profile", "profile__age") | 355 | num, err := o.QueryTable("user").Values(&maps, "id", "name", "profile", "profile__age") |
| 350 | if err != nil { | 356 | if err != nil { |
| 351 | fmt.Printf("Result Nums: %d\n", num) | 357 | fmt.Printf("Result Nums: %d\n", num) |
| 352 | for _, m := range maps { | 358 | for _, m := range maps { |
| 353 | fmt.Println(m["Id"], m["UserName"], m["Profile"], m["Profile__Age"]) | 359 | fmt.Println(m["Id"], m["Name"], m["Profile"], m["Profile__Age"]) |
| 354 | // map 中的数据都是展开的,没有复杂的嵌套 | 360 | // map 中的数据都是展开的,没有复杂的嵌套 |
| 355 | } | 361 | } |
| 356 | } | 362 | } |
| ... | @@ -379,11 +385,11 @@ if err != nil { | ... | @@ -379,11 +385,11 @@ if err != nil { |
| 379 | 385 | ||
| 380 | ```go | 386 | ```go |
| 381 | var lists []orm.ParamsList | 387 | var lists []orm.ParamsList |
| 382 | num, err := o.QueryTable("user").ValuesList(&lists, "user_name", "profile__age") | 388 | num, err := o.QueryTable("user").ValuesList(&lists, "name", "profile__age") |
| 383 | if err != nil { | 389 | if err != nil { |
| 384 | fmt.Printf("Result Nums: %d\n", num) | 390 | fmt.Printf("Result Nums: %d\n", num) |
| 385 | for _, row := range lists { | 391 | for _, row := range lists { |
| 386 | fmt.Printf("UserName: %s, Age: %s\m", row[0], row[1]) | 392 | fmt.Printf("Name: %s, Age: %s\m", row[0], row[1]) |
| 387 | } | 393 | } |
| 388 | } | 394 | } |
| 389 | ``` | 395 | ``` |
| ... | @@ -394,7 +400,7 @@ if err != nil { | ... | @@ -394,7 +400,7 @@ if err != nil { |
| 394 | 400 | ||
| 395 | ```go | 401 | ```go |
| 396 | var list orm.ParamsList | 402 | var list orm.ParamsList |
| 397 | num, err := o.QueryTable("user").ValuesFlat(&list, "user_name") | 403 | num, err := o.QueryTable("user").ValuesFlat(&list, "name") |
| 398 | if err != nil { | 404 | if err != nil { |
| 399 | fmt.Printf("Result Nums: %d\n", num) | 405 | fmt.Printf("Result Nums: %d\n", num) |
| 400 | fmt.Printf("All User Names: %s", strings.Join(list, ", ") | 406 | fmt.Printf("All User Names: %s", strings.Join(list, ", ") | ... | ... |
| 1 | ## 文档目录 | 1 | ## 文档目录 |
| 2 | 2 | ||
| 3 | 1. [模型定义](Models.md) | 3 | |
| 4 | - [支持的 Field 类型](Models.md#field-type) | 4 | 1. [Orm 使用方法](Orm.md) |
| 5 | - [Field 设置参数](Models.md#field-options) | 5 | - [数据库的设置](Orm.md#数据库的设置) |
| 6 | - [关系型 Field 设置](Models.md#relation-field-options) | 6 | - [ORM 接口使用](Orm.md#orm-接口使用) |
| 7 | 2. Custom Fields | 7 | 2. [对象的CRUD操作](Object.md) |
| 8 | 3. [Orm 使用方法](Orm.md) | 8 | 3. [高级查询](Query.md) |
| 9 | - [Ormer 接口](Orm.md#ormer) | 9 | - [使用的表达式语法](Query.md#expr) |
| 10 | 4. [对象操作](Object.md) | 10 | - [支持的操作符号](Query.md#operators) |
| 11 | 5. [复杂查询](Query.md) | 11 | - [高级查询接口使用](Query.md#高级查询接口使用) |
| 12 | - [查询使用的表达式语法](Query.md#expr) | 12 | 4. [使用SQL语句进行查询](Raw.md) |
| 13 | - [查询支持的操作符号](Query.md#operators) | 13 | 5. [事务处理](Transaction.md) |
| 14 | - [QuerySeter 接口](Query.md#queryseter) | 14 | 6. [模型定义](Models.md) |
| 15 | 6. Raw | 15 | - [Struct Tag 设置参数](Models.md#struct-tag-设置参数) |
| 16 | 7. Transaction | 16 | - [表关系设置](Models.md#表关系设置) |
| 17 | - [Struct Field 类型与数据库的对应](Models.md#struct-field-类型与数据库的对应) | ||
| 18 | 7. Custom Fields | ||
| 17 | 8. Faq | 19 | 8. Faq | ... | ... |
orm/docs/zh/Raw.md
0 → 100644
| 1 | ## 使用SQL语句进行查询 | ||
| 2 | |||
| 3 | 使用 Raw SQL 查询,无需使用 ORM 表定义 | ||
| 4 | |||
| 5 | 创建一个 **RawSeter** | ||
| 6 | |||
| 7 | ```go | ||
| 8 | o := NewOrm() | ||
| 9 | var r RawSeter | ||
| 10 | r = o.Raw("UPDATE user SET name = ? WHERE name = ?", "testing", "slene") | ||
| 11 | ``` | ||
| 12 | |||
| 13 | * type RawSeter interface { | ||
| 14 | * [Exec() (int64, error)](#exec) | ||
| 15 | * [QueryRow(...interface{}) error](#queryrow) | ||
| 16 | * [QueryRows(...interface{}) (int64, error)](#queryrows) | ||
| 17 | * [SetArgs(...interface{}) RawSeter](#setargs) | ||
| 18 | * [Values(*[]Params) (int64, error)](#values) | ||
| 19 | * [ValuesList(*[]ParamsList) (int64, error)](#valueslist) | ||
| 20 | * [ValuesFlat(*ParamsList) (int64, error)](#valuesflat) | ||
| 21 | * [Prepare() (RawPreparer, error)](#prepare) | ||
| 22 | * } | ||
| 23 | |||
| 24 | #### Exec | ||
| 25 | |||
| 26 | 执行sql语句 | ||
| 27 | |||
| 28 | ```go | ||
| 29 | num, err := r.Exec() | ||
| 30 | ``` | ||
| 31 | |||
| 32 | #### QueryRow | ||
| 33 | |||
| 34 | TODO | ||
| 35 | |||
| 36 | #### QueryRows | ||
| 37 | |||
| 38 | TODO | ||
| 39 | |||
| 40 | #### SetArgs | ||
| 41 | |||
| 42 | 改变 Raw(sql, args...) 中的 args 参数,返回一个新的 RawSeter | ||
| 43 | |||
| 44 | 用于单条 sql 语句,重复利用,替换参数然后执行。 | ||
| 45 | |||
| 46 | ```go | ||
| 47 | num, err := r.SetArgs("set name", "name1").Exec() | ||
| 48 | num, err := r.SetArgs("set name", "name2").Exec() | ||
| 49 | ``` | ||
| 50 | #### Values / ValuesList / ValuesFlat | ||
| 51 | |||
| 52 | Raw SQL 查询获得的结果集 Value 为 `string` 类型,NULL 字段的值为空 `` | ||
| 53 | |||
| 54 | #### Values | ||
| 55 | |||
| 56 | |||
| 57 | 返回结果集的 key => value 值 | ||
| 58 | |||
| 59 | ```go | ||
| 60 | var maps []orm.Params | ||
| 61 | num, err = o.Raw("SELECT user_name FROM user WHERE status = ?", 1).Values(&maps) | ||
| 62 | if err == nil && num > 0 { | ||
| 63 | fmt.Println(maps[0]["user_name"]) // slene | ||
| 64 | } | ||
| 65 | ``` | ||
| 66 | |||
| 67 | #### ValuesList | ||
| 68 | |||
| 69 | 返回结果集 slice | ||
| 70 | |||
| 71 | ```go | ||
| 72 | var lists []orm.ParamsList | ||
| 73 | num, err = o.Raw("SELECT user_name FROM user WHERE status = ?", 1).ValuesList(&lists) | ||
| 74 | if err == nil && num > 0 { | ||
| 75 | fmt.Println(lists[0][0]) // slene | ||
| 76 | } | ||
| 77 | ``` | ||
| 78 | |||
| 79 | #### ValuesFlat | ||
| 80 | |||
| 81 | 返回单一字段的平铺 slice 数据 | ||
| 82 | |||
| 83 | ```go | ||
| 84 | var list orm.ParamsList | ||
| 85 | num, err = o.Raw("SELECT id FROM user WHERE id < ?", 10).ValuesList(&list) | ||
| 86 | if err == nil && num > 0 { | ||
| 87 | fmt.Println(list) // []{"1","2","3",...} | ||
| 88 | } | ||
| 89 | ``` | ||
| 90 | |||
| 91 | #### Prepare | ||
| 92 | |||
| 93 | 用于一次 prepare 多次 exec,以提高批量执行的速度。 | ||
| 94 | |||
| 95 | ```go | ||
| 96 | p, err := o.Raw("UPDATE user SET name = ? WHERE name = ?").Prepare() | ||
| 97 | num, err := p.Exec("testing", "slene") | ||
| 98 | num, err = p.Exec("testing", "astaxie") | ||
| 99 | ... | ||
| 100 | ... | ||
| 101 | p.Close() // 别忘记关闭 statement | ||
| 102 | ``` | ||
| 103 | |||
| 104 | ## FAQ | ||
| 105 | |||
| 106 | 1. 我的 app 需要支持多类型数据库,如何在使用 Raw SQL 的时候判断当前使用的数据库类型。 | ||
| 107 | |||
| 108 | 使用 Ormer 的 [Driver方法](Orm.md#driver) 可以进行判断 |
orm/docs/zh/Transaction.md
0 → 100644
-
Please register or sign in to post a comment