improved get cascade bean

This commit is contained in:
Lunny Xiao 2017-04-04 17:05:49 +08:00
parent 590bb1015b
commit 0abbd9fb91
No known key found for this signature in database
GPG Key ID: C3B7C91B632F738A
6 changed files with 82 additions and 117 deletions

View File

@ -1,3 +1,7 @@
// Copyright 2017 The Xorm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package xorm
import (

View File

@ -931,6 +931,7 @@ func (engine *Engine) mapType(parsingTables map[reflect.Type]*core.Table, v refl
if ormTagStr != "" {
col = &core.Column{
FieldName: t.Field(i).Name,
FieldType: t.Field(i).Type,
Nullable: true,
IsPrimaryKey: false,
IsAutoIncrement: false,
@ -1044,6 +1045,7 @@ func (engine *Engine) mapType(parsingTables map[reflect.Type]*core.Table, v refl
col = core.NewColumn(
engine.ColumnMapper.Obj2Table(t.Field(i).Name),
t.Field(i).Name,
sqlType,
sqlType.DefaultLength,
sqlType.DefaultLength2,
@ -1054,6 +1056,7 @@ func (engine *Engine) mapType(parsingTables map[reflect.Type]*core.Table, v refl
idFieldColName = col.Name
}
col.FieldType = t.Field(i).Type
ctx.col = col
}
if col.IsAutoIncrement {

View File

@ -149,7 +149,7 @@ func (session *Session) Alias(alias string) *Session {
// NoCascade indicate that no cascade load child object
func (session *Session) NoCascade() *Session {
session.statement.cascadeMode = cascadeManuallyLoad
session.statement.cascadeMode = cascadeManually
return session
}
@ -204,12 +204,12 @@ func (session *Session) Charset(charset string) *Session {
// Cascade indicates if loading sub Struct
func (session *Session) Cascade(trueOrFalse ...bool) *Session {
var mode = cascadeAutoLoad
var mode = cascadeAuto
if len(trueOrFalse) >= 1 {
if trueOrFalse[0] {
mode = cascadeAutoLoad
mode = cascadeAuto
} else {
mode = cascadeManuallyLoad
mode = cascadeManually
}
}
@ -447,8 +447,8 @@ func (session *Session) slice2Bean(scanResults []interface{}, fields []string, b
continue
}
rawValueType := reflect.TypeOf(rawValue.Interface())
vv := reflect.ValueOf(rawValue.Interface())
rawValueType := vv.Type()
col := table.GetColumnIdx(key, idx)
if col.IsPrimaryKey {
pk = append(pk, rawValue.Interface())
@ -639,35 +639,25 @@ func (session *Session) slice2Bean(scanResults []interface{}, fields []string, b
} else if (col.AssociateType == core.AssociateNone &&
session.statement.cascadeMode == cascadeCompitable) ||
(col.AssociateType == core.AssociateBelongsTo &&
session.statement.cascadeMode == cascadeAutoLoad) {
table := col.AssociateTable
hasAssigned = true
if len(table.PrimaryKeys) != 1 {
return nil, errors.New("unsupported non or composited primary key cascade")
}
var pk = make(core.PK, len(table.PrimaryKeys))
session.statement.cascadeMode == cascadeAuto) {
var pk = make(core.PK, len(col.AssociateTable.PrimaryKeys))
var err error
pk[0], err = asKind(vv, rawValueType)
rawValueType := col.AssociateTable.PKColumns()[0].FieldType
if rawValueType.Kind() == reflect.Ptr {
pk[0] = reflect.New(rawValueType.Elem()).Interface()
} else {
pk[0] = reflect.New(rawValueType).Interface()
}
err = convertAssign(pk[0], vv.Interface())
if err != nil {
return nil, err
}
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())
has, err := session.ID(pk).NoCascade().get(structInter.Interface())
if err != nil {
return nil, err
}
if has {
fieldValue.Set(structInter.Elem())
} else {
return nil, errors.New("cascade obj is not exist")
}
pk[0] = reflect.ValueOf(pk[0]).Elem().Interface()
if err = session.getByPK(pk, fieldValue); err != nil {
return nil, err
}
hasAssigned = true
} else if col.AssociateType == core.AssociateBelongsTo {
hasAssigned = true
err := convertAssign(fieldValue.FieldByName(table.PKColumns()[0].FieldName).Addr().Interface(),
@ -681,47 +671,25 @@ func (session *Session) slice2Bean(scanResults []interface{}, fields []string, b
if (col.AssociateType == core.AssociateNone &&
session.statement.cascadeMode == cascadeCompitable) ||
(col.AssociateType == core.AssociateBelongsTo &&
session.statement.cascadeMode == cascadeAutoLoad) {
table := col.AssociateTable
hasAssigned = true
if len(table.PrimaryKeys) != 1 {
panic("unsupported non or composited primary key cascade")
}
var pk = make(core.PK, len(table.PrimaryKeys))
session.statement.cascadeMode == cascadeAuto) {
var pk = make(core.PK, len(col.AssociateTable.PrimaryKeys))
var err error
pk[0], err = asKind(vv, rawValueType)
rawValueType := col.AssociateTable.ColumnType(col.AssociateTable.PKColumns()[0].FieldName)
if rawValueType.Kind() == reflect.Ptr {
pk[0] = reflect.New(rawValueType.Elem()).Interface()
} else {
pk[0] = reflect.New(rawValueType).Interface()
}
err = convertAssign(pk[0], vv.Interface())
if err != nil {
return nil, err
}
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
var structInter reflect.Value
if fieldValue.Kind() == reflect.Ptr {
if fieldValue.IsNil() {
structInter = reflect.New(fieldValue.Type().Elem())
} else {
structInter = *fieldValue
}
} else {
structInter = fieldValue.Addr()
}
has, err := session.ID(pk).NoCascade().get(structInter.Interface())
if err != nil {
return nil, err
}
if has {
if fieldValue.Kind() == reflect.Ptr && fieldValue.IsNil() {
fieldValue.Set(structInter)
}
} else {
return nil, errors.New("cascade obj is not exist")
}
pk[0] = reflect.ValueOf(pk[0]).Elem().Interface()
if err = session.getByPK(pk, fieldValue); err != nil {
return nil, err
}
hasAssigned = true
} else if col.AssociateType == core.AssociateBelongsTo {
hasAssigned = true
if fieldValue.IsNil() {
@ -873,6 +841,34 @@ func (session *Session) slice2Bean(scanResults []interface{}, fields []string, b
return pk, nil
}
func (session *Session) getByPK(pk core.PK, fieldValue *reflect.Value) error {
if !isPKZero(pk) {
var structInter reflect.Value
if fieldValue.Kind() == reflect.Ptr {
if fieldValue.IsNil() {
structInter = reflect.New(fieldValue.Type().Elem())
} else {
structInter = *fieldValue
}
} else {
structInter = fieldValue.Addr()
}
has, err := session.ID(pk).NoCascade().get(structInter.Interface())
if err != nil {
return err
}
if has {
if fieldValue.Kind() == reflect.Ptr && fieldValue.IsNil() {
fieldValue.Set(structInter)
}
} else {
return errors.New("cascade obj is not exist")
}
}
return nil
}
// saveLastSQL stores executed query information
func (session *Session) saveLastSQL(sql string, args ...interface{}) {
session.lastSQL = sql

View File

@ -8,7 +8,6 @@ import (
"database/sql"
"database/sql/driver"
"encoding/json"
"errors"
"fmt"
"reflect"
"strconv"
@ -206,37 +205,18 @@ func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value,
} else if (col.AssociateType == core.AssociateNone &&
session.statement.cascadeMode == cascadeCompitable) ||
(col.AssociateType == core.AssociateBelongsTo &&
session.statement.cascadeMode == cascadeAutoLoad) {
table := col.AssociateTable
// TODO: current only support 1 primary key
if len(table.PrimaryKeys) > 1 {
return errors.New("unsupported composited primary key cascade")
}
var pk = make(core.PK, len(table.PrimaryKeys))
rawValueType := table.ColumnType(table.PKColumns()[0].FieldName)
session.statement.cascadeMode == cascadeAuto) {
var pk = make(core.PK, len(col.AssociateTable.PrimaryKeys))
// only 1 PK checked on tag parsing
rawValueType := col.AssociateTable.ColumnType(col.AssociateTable.PKColumns()[0].FieldName)
var err error
pk[0], err = str2PK(string(data), rawValueType)
if err != nil {
return err
}
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())
has, err := session.ID(pk).NoCascade().get(structInter.Interface())
if err != nil {
return err
}
if has {
v = structInter.Elem().Interface()
fieldValue.Set(reflect.ValueOf(v))
} else {
return errors.New("cascade obj is not exist")
}
if err = session.getByPK(pk, fieldValue); err != nil {
return err
}
}
}
@ -489,35 +469,18 @@ func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value,
if (col.AssociateType == core.AssociateNone &&
session.statement.cascadeMode == cascadeCompitable) ||
(col.AssociateType == core.AssociateBelongsTo &&
session.statement.cascadeMode == cascadeAutoLoad) {
table := col.AssociateTable
if len(table.PrimaryKeys) > 1 {
return errors.New("unsupported composited primary key cascade")
}
var pk = make(core.PK, len(table.PrimaryKeys))
session.statement.cascadeMode == cascadeAuto) {
var pk = make(core.PK, len(col.AssociateTable.PrimaryKeys))
var err error
rawValueType := table.ColumnType(table.PKColumns()[0].FieldName)
// only 1 PK checked on tag parsing
rawValueType := col.AssociateTable.ColumnType(col.AssociateTable.PKColumns()[0].FieldName)
pk[0], err = str2PK(string(data), rawValueType)
if err != nil {
return err
}
if !isPKZero(pk) {
structInter := reflect.New(fieldType.Elem())
// !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
has, err := session.ID(pk).NoCascade().get(structInter.Interface())
if err != nil {
return err
}
if has {
v = structInter.Interface()
fieldValue.Set(reflect.ValueOf(v))
} else {
return errors.New("cascade obj is not exist")
}
if err = session.getByPK(pk, fieldValue); err != nil {
return err
}
}
}

View File

@ -172,9 +172,8 @@ func (session *Session) noCacheFind(table *core.Table, containerValue reflect.Va
var newElemFunc func(fields []string) reflect.Value
elemType := containerValue.Type().Elem()
var isPointer bool
if elemType.Kind() == reflect.Ptr {
isPointer = true
var isPointer = elemType.Kind() == reflect.Ptr
if isPointer {
elemType = elemType.Elem()
}
if elemType.Kind() == reflect.Ptr {

View File

@ -37,8 +37,8 @@ type cascadeMode int
const (
cascadeCompitable cascadeMode = iota
cascadeAutoLoad
cascadeManuallyLoad
cascadeAuto
cascadeManually
)
// Statement save all the sql info for executing SQL