bug fixed & add MustCols function & improved docs

This commit is contained in:
Lunny Xiao 2014-04-06 12:58:16 +08:00
parent 6e7cead1ec
commit 9d5f834eb2
6 changed files with 179 additions and 41 deletions

View File

@ -372,8 +372,8 @@ func update(engine *Engine, t *testing.T) {
}
type UpdateAllCols struct {
Id int64
Bool bool
Id int64
Bool bool
String string
}
@ -383,7 +383,7 @@ func update(engine *Engine, t *testing.T) {
t.Error(err)
panic(err)
}
_, err = engine.Insert(col1)
if err != nil {
t.Error(err)
@ -417,6 +417,57 @@ func update(engine *Engine, t *testing.T) {
panic(err)
return
}
{
type UpdateMustCols struct {
Id int64
Bool bool
String string
}
col1 := &UpdateMustCols{}
err = engine.Sync(col1)
if err != nil {
t.Error(err)
panic(err)
}
_, err = engine.Insert(col1)
if err != nil {
t.Error(err)
panic(err)
}
col2 := &UpdateMustCols{col1.Id, true, ""}
boolStr := engine.columnMapper.Obj2Table("Bool")
stringStr := engine.columnMapper.Obj2Table("String")
_, err = engine.Id(col2.Id).MustCols(boolStr, stringStr).Update(col2)
if err != nil {
t.Error(err)
panic(err)
}
col3 := &UpdateMustCols{}
has, err := engine.Id(col2.Id).Get(col3)
if err != nil {
t.Error(err)
panic(err)
}
if !has {
err = errors.New(fmt.Sprintf("cannot get id %d", col2.Id))
t.Error(err)
panic(err)
return
}
if *col2 != *col3 {
err = errors.New(fmt.Sprintf("col2 should eq col3"))
t.Error(err)
panic(err)
return
}
}
}
func updateSameMapper(engine *Engine, t *testing.T) {

View File

@ -4,7 +4,7 @@ xorm 快速入门
* [1.创建Orm引擎](#10)
* [2.定义表结构体](#20)
* [2.1.名称映射规则](#21)
* [2.2.前缀映射规则和后缀映射规则](#22)
* [2.2.前缀映射,后缀映射和缓存映射](#22)
* [2.3.使用Table和Tag改变名称映射](#23)
* [2.4.Column属性定义](#24)
* [2.5.Go与字段类型对应表](#25)
@ -29,12 +29,13 @@ xorm 快速入门
* [9.执行SQL命令](#100)
* [10.事务处理](#110)
* [11.缓存](#120)
* [12.xorm工具](#130)
* [12.1.反转命令](#131)
* [13.Examples](#140)
* [14.案例](#150)
* [15.那些年我们踩过的坑](#160)
* [16.讨论](#170)
* [12.事件](#125)
* [13.xorm工具](#130)
* [13.1.反转命令](#131)
* [14.Examples](#140)
* [15.案例](#150)
* [16.那些年我们踩过的坑](#160)
* [17.讨论](#170)
<a name="10" id="10"></a>
## 1.创建Orm引擎
@ -129,11 +130,11 @@ engine.SetColumnMapper(SnakeMapper{})
```
<a name="22" id="22"></a>
### 2.2.前缀映射规则和后缀映射规则
### 2.2.前缀映射,后缀映射和缓存映射
* 通过`engine.NewPrefixMapper(SnakeMapper{}, "prefix")`可以在SnakeMapper的基础上在命名中添加统一的前缀当然也可以把SnakeMapper{}换成SameMapper或者你自定义的Mapper。
* 通过`engine.NewSufffixMapper(SnakeMapper{}, "suffix")`可以在SnakeMapper的基础上在命名中添加统一的后缀当然也可以把SnakeMapper{}换成SameMapper或者你自定义的Mapper。
*
* 通过`eneing.NewCacheMapper(SnakeMapper{})`可以组合其它的映射规则,起到在内存中缓存曾经映射过的命名映射。
<a name="23" id="23"></a>
### 2.3.使用Table和Tag改变名称映射
@ -153,7 +154,7 @@ type User struct {
}
```
对于不同的数据库系统数据类型其实是有些差异的。因此xorm中对数据类型有自己的定义基本的原则是尽量兼容各种数据库的字段类型具体的字段对应关系可以查看[字段类型对应表](https://github.com/lunny/xorm/blob/master/docs/COLUMNTYPE.md)。
对于不同的数据库系统数据类型其实是有些差异的。因此xorm中对数据类型有自己的定义基本的原则是尽量兼容各种数据库的字段类型具体的字段对应关系可以查看[字段类型对应表](https://github.com/lunny/xorm/blob/master/docs/COLUMNTYPE.md)。对于使用者,一般只要使用自己熟悉的数据库字段定义即可。
具体的映射规则如下另Tag中的关键字均不区分大小写字段名区分大小写
@ -407,7 +408,11 @@ engine.Cols("age", "name").Update(&user)
// UPDATE user SET age=? AND name=?
```
其中的参数"age", "name"也可以写成"age, name",两种写法均可
* AllCols()
查询或更新所有字段。
* MustCols(…string)
某些字段必须更新。
* Omit(...string)
和cols相反此函数指定排除某些指定的字段。注意此方法和Cols方法不可同时使用
@ -729,20 +734,46 @@ engine.ClearCache(new(User))
![cache design](https://raw.github.com/lunny/xorm/master/docs/cache_design.png)
<a name="125" id="125"></a>
## 12.事件
xorm支持两种方式的事件一种是在Struct中的特定方法来作为事件的方法一种是在执行语句的过程中执行事件。
在Struct中作为成员方法的事件如下
* BeforeInsert()
* BeforeUpdate()
* BeforeDelete()
* AfterInsert()
* AfterUpdate()
* AfterDelete()
在语句执行过程中的事件方法为:
* Before(beforeFunc interface{})
* After(afterFunc interface{})
其中beforeFunc和afterFunc的原型为func(bean interface{}).
<a name="130" id="130"></a>
## 12.xorm工具
## 13.xorm工具
xorm工具提供了xorm命令能够帮助做很多事情。
### 12.1.反转命令
### 13.1.反转命令
参见 [xorm工具](https://github.com/lunny/xorm/tree/master/xorm)
<a name="140" id="140"></a>
## 13.Examples
## 14.Examples
请访问[https://github.com/lunny/xorm/tree/master/examples](https://github.com/lunny/xorm/tree/master/examples)
<a name="150" id="150"></a>
## 14.案例
## 15.案例
* [Gowalker](http://gowalker.org),源代码 [github.com/Unknwon/gowalker](http://github.com/Unknwon/gowalker)
@ -753,7 +784,7 @@ xorm工具提供了xorm命令能够帮助做很多事情。
* [VeryHour](http://veryhour.com)
<a name="160" id="160"></a>
## 15.那些年我们踩过的坑
## 16.那些年我们踩过的坑
* 怎么同时使用xorm的tag和json的tag
答:使用空格
@ -797,5 +828,5 @@ money float64 `xorm:"Numeric"`
<a name="170" id="170"></a>
## 16.讨论
## 17.讨论
请加入QQ群280360085 进行讨论。

View File

@ -100,30 +100,47 @@ engine.Logger = f
<a name="20" id="20"></a>
## 2.Define struct
xorm支持将一个struct映射为数据库中对应的一张表。映射规则如下
xorm map a struct to a database table, the rule is below.
<a name="21" id="21"></a>
### 2.1.名称映射规则
### 2.1.name mapping rule
名称映射规则主要负责结构体名称到表名和结构体field到表字段的名称映射。由xorm.IMapper接口的实现者来管理xorm内置了两种IMapper实现`SnakeMapper` 和 `SameMapper`。SnakeMapper支持struct为驼峰式命名表结构为下划线命名之间的转换SameMapper支持相同的命名。
use xorm.IMapper interface to implement. There are two IMapper implemented: `SnakeMapper` and `SameMapper`. SnakeMapper means struct name is word by word and table name or column name as 下划线. SameMapper means same name between struct and table.
当前SnakeMapper为默认值如果需要改变时在engine创建完成后使用
SnakeMapper is the default.
```Go
engine.Mapper = SameMapper{}
```
同时需要注意的是:
* 如果你使用了别的命名规则映射方案也可以自己实现一个IMapper。
* 表名称和字段名称的映射规则默认是相同的,当然也可以设置为不同,如:
```Go
engine.SetTableMapper(SameMapper{})
engine.SetColumnMapper(SnakeMapper{})
```
<a name="22" id="22"></a>
### 2.2.前缀映射规则,后缀映射规则和缓存映射规则
* 通过`engine.NewPrefixMapper(SnakeMapper{}, "prefix")`可以在SnakeMapper的基础上在命名中添加统一的前缀当然也可以把SnakeMapper{}换成SameMapper或者你自定义的Mapper。
* 通过`engine.NewSufffixMapper(SnakeMapper{}, "suffix")`可以在SnakeMapper的基础上在命名中添加统一的后缀当然也可以把SnakeMapper{}换成SameMapper或者你自定义的Mapper。
* 通过`eneing.NewCacheMapper(SnakeMapper{})`可以起到在内存中缓存曾经映射过的命名映射。
当然如果你使用了别的命名规则映射方案也可以自己实现一个IMapper。
<a name="22" id="22"></a>
### 2.2.使用Table和Tag改变名称映射
### 2.3.使用Table和Tag改变名称映射
如果所有的命名都是按照IMapper的映射来操作的那当然是最理想的。但是如果碰到某个表名或者某个字段名跟映射规则不匹配时我们就需要别的机制来改变。
通过`engine.Table()`方法可以改变struct对应的数据库表的名称通过sturct中field对应的Tag中使用`xorm:"'table_name'"`可以使该field对应的Column名称为指定名称。这里使用两个单引号将Column名称括起来是为了防止名称冲突因为我们在Tag中还可以对这个Column进行更多的定义。如果名称不冲突的情况单引号也可以不使用。
<a name="23" id="23"></a>
### 2.3.Column属性定义
### 2.4.Column属性定义
我们在field对应的Tag中对Column的一些属性进行定义定义的方法基本和我们写SQL定义表结构类似比如
```

View File

@ -336,6 +336,18 @@ func (engine *Engine) Cols(columns ...string) *Session {
return session.Cols(columns...)
}
func (engine *Engine) AllCols() *Session {
session := engine.NewSession()
session.IsAutoClose = true
return session.AllCols()
}
func (engine *Engine) MustCols(columns ...string) *Session {
session := engine.NewSession()
session.IsAutoClose = true
return session.MustCols(columns...)
}
// Xorm automatically retrieve condition according struct, but
// if struct has bool field, it will ignore them. So use UseBool
// to tell system to do not ignore them.

View File

@ -131,6 +131,11 @@ func (session *Session) AllCols() *Session {
return session
}
func (session *Session) MustCols(columns ...string) *Session {
session.Statement.MustCols(columns...)
return session
}
func (session *Session) NoCascade() *Session {
session.Statement.UseCascade = false
return session
@ -1029,7 +1034,7 @@ func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{})
if len(condiBean) > 0 {
colNames, args := buildConditions(session.Engine, table, condiBean[0], true, true,
false, true, session.Statement.allUseBool, session.Statement.useAllCols,
session.Statement.boolColumnMap)
session.Statement.mustColumnMap)
session.Statement.ConditionStr = strings.Join(colNames, " AND ")
session.Statement.BeanArgs = args
}
@ -2845,7 +2850,7 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
if session.Statement.ColumnStr == "" {
colNames, args = buildConditions(session.Engine, table, bean, false, false,
false, false, session.Statement.allUseBool, session.Statement.useAllCols,
session.Statement.boolColumnMap)
session.Statement.mustColumnMap)
} else {
colNames, args, err = table.genCols(session, bean, true, true)
if err != nil {
@ -2880,7 +2885,7 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
if len(condiBean) > 0 {
condiColNames, condiArgs = buildConditions(session.Engine, session.Statement.RefTable, condiBean[0], true, true,
false, true, session.Statement.allUseBool, session.Statement.useAllCols,
session.Statement.boolColumnMap)
session.Statement.mustColumnMap)
}
var condition = ""
@ -3069,7 +3074,7 @@ func (session *Session) Delete(bean interface{}) (int64, error) {
session.Statement.RefTable = table
colNames, args := buildConditions(session.Engine, table, bean, true, true,
false, true, session.Statement.allUseBool, session.Statement.useAllCols,
session.Statement.boolColumnMap)
session.Statement.mustColumnMap)
var condition = ""

View File

@ -41,7 +41,7 @@ type Statement struct {
IsDistinct bool
allUseBool bool
checkVersion bool
boolColumnMap map[string]bool
mustColumnMap map[string]bool
inColumns map[string][]interface{}
}
@ -70,7 +70,7 @@ func (statement *Statement) Init() {
statement.UseAutoTime = true
statement.IsDistinct = false
statement.allUseBool = false
statement.boolColumnMap = make(map[string]bool)
statement.mustColumnMap = make(map[string]bool)
statement.checkVersion = true
statement.inColumns = make(map[string][]interface{})
}
@ -242,7 +242,7 @@ func (statement *Statement) Table(tableNameOrBean interface{}) *Statement {
func buildConditions(engine *Engine, table *Table, bean interface{},
includeVersion bool, includeUpdated bool, includeNil bool,
includeAutoIncr bool, allUseBool bool, useAllCols bool,
boolColumnMap map[string]bool) ([]string, []interface{}) {
mustColumnMap map[string]bool) ([]string, []interface{}) {
colNames := make([]string, 0)
var args = make([]interface{}, 0)
@ -265,6 +265,14 @@ func buildConditions(engine *Engine, table *Table, bean interface{},
fieldType := reflect.TypeOf(fieldValue.Interface())
requiredField := useAllCols
if b, ok := mustColumnMap[strings.ToLower(col.Name)]; ok {
if b {
requiredField = true
} else {
continue
}
}
if fieldType.Kind() == reflect.Ptr {
if fieldValue.IsNil() {
if includeNil {
@ -287,8 +295,6 @@ func buildConditions(engine *Engine, table *Table, bean interface{},
case reflect.Bool:
if allUseBool || requiredField {
val = fieldValue.Interface()
} else if _, ok := boolColumnMap[col.Name]; ok {
val = fieldValue.Interface()
} else {
// if a bool in a struct, it will not be as a condition because it default is false,
// please use Where() instead
@ -519,18 +525,34 @@ func (statement *Statement) Cols(columns ...string) *Statement {
return statement
}
// Update use only: update all columns
func (statement *Statement) AllCols() *Statement {
statement.useAllCols = true
return statement
}
// Update use only: must update columns
func (statement *Statement) MustCols(columns ...string) *Statement {
newColumns := col2NewCols(columns...)
for _, nc := range newColumns {
statement.mustColumnMap[strings.ToLower(nc)] = true
}
return statement
}
// Update use only: not update columns
/*func (statement *Statement) NotCols(columns ...string) *Statement {
newColumns := col2NewCols(columns...)
for _, nc := range newColumns {
statement.mustColumnMap[strings.ToLower(nc)] = false
}
return statement
}*/
// indicates that use bool fields as update contents and query contiditions
func (statement *Statement) UseBool(columns ...string) *Statement {
if len(columns) > 0 {
newColumns := col2NewCols(columns...)
for _, nc := range newColumns {
statement.boolColumnMap[strings.ToLower(nc)] = true
}
statement.MustCols(columns...)
} else {
statement.allUseBool = true
}
@ -721,7 +743,7 @@ func (statement *Statement) genGetSql(bean interface{}) (string, []interface{})
colNames, args := buildConditions(statement.Engine, table, bean, true, true,
false, true, statement.allUseBool, statement.useAllCols,
statement.boolColumnMap)
statement.mustColumnMap)
statement.ConditionStr = strings.Join(colNames, " AND ")
statement.BeanArgs = args
@ -760,7 +782,7 @@ func (statement *Statement) genCountSql(bean interface{}) (string, []interface{}
statement.RefTable = table
colNames, args := buildConditions(statement.Engine, table, bean, true, true, false,
true, statement.allUseBool, statement.useAllCols, statement.boolColumnMap)
true, statement.allUseBool, statement.useAllCols, statement.mustColumnMap)
statement.ConditionStr = strings.Join(colNames, " AND ")
statement.BeanArgs = args