improved get cascade bean
This commit is contained in:
parent
590bb1015b
commit
0abbd9fb91
|
@ -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 (
|
||||
|
|
|
@ -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 {
|
||||
|
|
122
session.go
122
session.go
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -37,8 +37,8 @@ type cascadeMode int
|
|||
|
||||
const (
|
||||
cascadeCompitable cascadeMode = iota
|
||||
cascadeAutoLoad
|
||||
cascadeManuallyLoad
|
||||
cascadeAuto
|
||||
cascadeManually
|
||||
)
|
||||
|
||||
// Statement save all the sql info for executing SQL
|
||||
|
|
Loading…
Reference in New Issue