add cascade non-int64 primary key support & bug fixed #178

This commit is contained in:
Lunny Xiao 2015-02-22 23:52:53 +08:00
parent 7e3812ca28
commit 5cdb680945
5 changed files with 236 additions and 22 deletions

View File

@ -990,8 +990,12 @@ func (engine *Engine) IsTableExist(beanOrTableName interface{}) (bool, error) {
}
func (engine *Engine) IdOf(bean interface{}) core.PK {
table := engine.TableInfo(bean)
v := reflect.Indirect(reflect.ValueOf(bean))
return engine.IdOfV(reflect.ValueOf(bean))
}
func (engine *Engine) IdOfV(rv reflect.Value) core.PK {
v := reflect.Indirect(rv)
table := engine.autoMapType(v)
pk := make([]interface{}, len(table.PrimaryKeys))
for i, col := range table.PKColumns() {
pkField := v.FieldByName(col.FieldName)

View File

@ -11,6 +11,43 @@ import (
"github.com/go-xorm/core"
)
func isZero(k interface{}) bool {
switch k.(type) {
case int:
return k.(int) == 0
case int8:
return k.(int8) == 0
case int16:
return k.(int16) == 0
case int32:
return k.(int32) == 0
case int64:
return k.(int64) == 0
case uint:
return k.(uint) == 0
case uint8:
return k.(uint8) == 0
case uint16:
return k.(uint16) == 0
case uint32:
return k.(uint32) == 0
case uint64:
return k.(uint64) == 0
case string:
return k.(string) == ""
}
return false
}
func isPKZero(pk core.PK) bool {
for _, k := range pk {
if isZero(k) {
return true
}
}
return false
}
func indexNoCase(s, sep string) int {
return strings.Index(strings.ToLower(s), strings.ToLower(sep))
}

View File

@ -218,6 +218,9 @@ func (db *mysql) SqlType(c *core.Column) string {
res += ")"
case core.NVarchar:
res = core.Varchar
case core.Uuid:
res = core.Varchar
c.Length = 40
default:
res = t
}

View File

@ -648,11 +648,6 @@ func (session *Session) cacheGet(bean interface{}, sqlStr string, args ...interf
return false, ErrCacheFailed
}
// TODO: remove this after support multi pk cache
/*if len(session.Statement.RefTable.PrimaryKeys) != 1 {
return false, ErrCacheFailed
}*/
for _, filter := range session.Engine.dialect.Filters() {
sqlStr = filter.Do(sqlStr, session.Engine.dialect, session.Statement.RefTable)
}
@ -1775,18 +1770,45 @@ func (session *Session) _row2Bean(rows *core.Rows, fields []string, fieldsCount
} else if session.Statement.UseCascade {
table := session.Engine.autoMapType(*fieldValue)
if table != nil {
var x int64
if rawValueType.Kind() == reflect.Int64 {
x = vv.Int()
if len(table.PrimaryKeys) > 1 {
panic("unsupported composited primary key cascade")
}
if x != 0 {
var pk = make(core.PK, len(table.PrimaryKeys))
switch rawValueType.Kind() {
case reflect.Int64:
pk[0] = vv.Int()
case reflect.Int:
pk[0] = int(vv.Int())
case reflect.Int32:
pk[0] = int32(vv.Int())
case reflect.Int16:
pk[0] = int16(vv.Int())
case reflect.Int8:
pk[0] = int8(vv.Int())
case reflect.Uint64:
pk[0] = vv.Uint()
case reflect.Uint:
pk[0] = uint(vv.Uint())
case reflect.Uint32:
pk[0] = uint32(vv.Uint())
case reflect.Uint16:
pk[0] = uint16(vv.Uint())
case reflect.Uint8:
pk[0] = uint8(vv.Uint())
case reflect.String:
pk[0] = vv.String()
default:
panic("unsupported primary key type cascade")
}
if !isPKZero(pk) {
// !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
// property to be fetched lazily
structInter := reflect.New(fieldValue.Type())
newsession := session.Engine.NewSession()
defer newsession.Close()
has, err := newsession.Id(x).Get(structInter.Interface())
has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface())
if err != nil {
return err
}
@ -2415,18 +2437,86 @@ func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value,
} else if session.Statement.UseCascade {
table := session.Engine.autoMapType(*fieldValue)
if table != nil {
x, err := strconv.ParseInt(string(data), 10, 64)
if err != nil {
return fmt.Errorf("arg %v as int: %s", key, err.Error())
if len(table.PrimaryKeys) > 1 {
panic("unsupported composited primary key cascade")
}
if x != 0 {
var pk = make(core.PK, len(table.PrimaryKeys))
rawValueType := table.ColumnType(table.PKColumns()[0].FieldName)
switch rawValueType.Kind() {
case reflect.Int64:
x, err := strconv.ParseInt(string(data), 10, 64)
if err != nil {
return fmt.Errorf("arg %v as int: %s", key, err.Error())
}
pk[0] = x
case reflect.Int:
x, err := strconv.ParseInt(string(data), 10, 64)
if err != nil {
return fmt.Errorf("arg %v as int: %s", key, err.Error())
}
pk[0] = int(x)
case reflect.Int32:
x, err := strconv.ParseInt(string(data), 10, 64)
if err != nil {
return fmt.Errorf("arg %v as int: %s", key, err.Error())
}
pk[0] = int32(x)
case reflect.Int16:
x, err := strconv.ParseInt(string(data), 10, 64)
if err != nil {
return fmt.Errorf("arg %v as int: %s", key, err.Error())
}
pk[0] = int16(x)
case reflect.Int8:
x, err := strconv.ParseInt(string(data), 10, 64)
if err != nil {
return fmt.Errorf("arg %v as int: %s", key, err.Error())
}
pk[0] = int8(x)
case reflect.Uint64:
x, err := strconv.ParseUint(string(data), 10, 64)
if err != nil {
return fmt.Errorf("arg %v as int: %s", key, err.Error())
}
pk[0] = x
case reflect.Uint:
x, err := strconv.ParseUint(string(data), 10, 64)
if err != nil {
return fmt.Errorf("arg %v as int: %s", key, err.Error())
}
pk[0] = uint(x)
case reflect.Uint32:
x, err := strconv.ParseUint(string(data), 10, 64)
if err != nil {
return fmt.Errorf("arg %v as int: %s", key, err.Error())
}
pk[0] = uint32(x)
case reflect.Uint16:
x, err := strconv.ParseUint(string(data), 10, 64)
if err != nil {
return fmt.Errorf("arg %v as int: %s", key, err.Error())
}
pk[0] = uint16(x)
case reflect.Uint8:
x, err := strconv.ParseUint(string(data), 10, 64)
if err != nil {
return fmt.Errorf("arg %v as int: %s", key, err.Error())
}
pk[0] = uint8(x)
case reflect.String:
pk[0] = string(data)
default:
panic("unsupported primary key type cascade")
}
if !isPKZero(pk) {
// !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
// property to be fetched lazily
structInter := reflect.New(fieldValue.Type())
newsession := session.Engine.NewSession()
defer newsession.Close()
has, err := newsession.Id(x).Get(structInter.Interface())
has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface())
if err != nil {
return err
}
@ -2690,17 +2780,95 @@ func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value,
structInter := reflect.New(fieldType.Elem())
table := session.Engine.autoMapType(structInter.Elem())
if table != nil {
x, err := strconv.ParseInt(string(data), 10, 64)
if err != nil {
return fmt.Errorf("arg %v as int: %s", key, err.Error())
if len(table.PrimaryKeys) > 1 {
panic("unsupported composited primary key cascade")
}
if x != 0 {
var pk = make(core.PK, len(table.PrimaryKeys))
rawValueType := table.ColumnType(table.PKColumns()[0].FieldName)
switch rawValueType.Kind() {
case reflect.Int64:
x, err := strconv.ParseInt(string(data), 10, 64)
if err != nil {
return fmt.Errorf("arg %v as int: %s", key, err.Error())
}
pk[0] = x
case reflect.Int:
x, err := strconv.ParseInt(string(data), 10, 64)
if err != nil {
return fmt.Errorf("arg %v as int: %s", key, err.Error())
}
pk[0] = int(x)
case reflect.Int32:
x, err := strconv.ParseInt(string(data), 10, 64)
if err != nil {
return fmt.Errorf("arg %v as int: %s", key, err.Error())
}
pk[0] = int32(x)
case reflect.Int16:
x, err := strconv.ParseInt(string(data), 10, 64)
if err != nil {
return fmt.Errorf("arg %v as int: %s", key, err.Error())
}
pk[0] = int16(x)
case reflect.Int8:
x, err := strconv.ParseInt(string(data), 10, 64)
if err != nil {
return fmt.Errorf("arg %v as int: %s", key, err.Error())
}
pk[0] = x
case reflect.Uint64:
x, err := strconv.ParseUint(string(data), 10, 64)
if err != nil {
return fmt.Errorf("arg %v as int: %s", key, err.Error())
}
pk[0] = x
case reflect.Uint:
x, err := strconv.ParseUint(string(data), 10, 64)
if err != nil {
return fmt.Errorf("arg %v as int: %s", key, err.Error())
}
pk[0] = uint(x)
case reflect.Uint32:
x, err := strconv.ParseUint(string(data), 10, 64)
if err != nil {
return fmt.Errorf("arg %v as int: %s", key, err.Error())
}
pk[0] = uint32(x)
case reflect.Uint16:
x, err := strconv.ParseUint(string(data), 10, 64)
if err != nil {
return fmt.Errorf("arg %v as int: %s", key, err.Error())
}
pk[0] = uint16(x)
case reflect.Uint8:
x, err := strconv.ParseUint(string(data), 10, 64)
if err != nil {
return fmt.Errorf("arg %v as int: %s", key, err.Error())
}
pk[0] = uint8(x)
case reflect.String:
pk[0] = string(data)
default:
panic("unsupported primary key type cascade")
}
if !isPKZero(pk) {
// !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
// property to be fetched lazily
newsession := session.Engine.NewSession()
defer newsession.Close()
has, err := newsession.Id(x).Get(structInter.Interface())
has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface())
if err != nil {
return err
}

View File

@ -589,6 +589,8 @@ func buildConditions(engine *Engine, table *core.Table, bean interface{},
continue
}
val = engine.FormatTime(col.SQLType.Name, t)
} else if _, ok := reflect.New(fieldType).Interface().(core.Conversion); ok {
continue
} else {
engine.autoMapType(fieldValue)
if table, ok := engine.Tables[fieldValue.Type()]; ok {