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
|
package xorm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
@ -931,6 +931,7 @@ func (engine *Engine) mapType(parsingTables map[reflect.Type]*core.Table, v refl
|
||||||
if ormTagStr != "" {
|
if ormTagStr != "" {
|
||||||
col = &core.Column{
|
col = &core.Column{
|
||||||
FieldName: t.Field(i).Name,
|
FieldName: t.Field(i).Name,
|
||||||
|
FieldType: t.Field(i).Type,
|
||||||
Nullable: true,
|
Nullable: true,
|
||||||
IsPrimaryKey: false,
|
IsPrimaryKey: false,
|
||||||
IsAutoIncrement: false,
|
IsAutoIncrement: false,
|
||||||
|
@ -1044,6 +1045,7 @@ func (engine *Engine) mapType(parsingTables map[reflect.Type]*core.Table, v refl
|
||||||
col = core.NewColumn(
|
col = core.NewColumn(
|
||||||
engine.ColumnMapper.Obj2Table(t.Field(i).Name),
|
engine.ColumnMapper.Obj2Table(t.Field(i).Name),
|
||||||
t.Field(i).Name,
|
t.Field(i).Name,
|
||||||
|
|
||||||
sqlType,
|
sqlType,
|
||||||
sqlType.DefaultLength,
|
sqlType.DefaultLength,
|
||||||
sqlType.DefaultLength2,
|
sqlType.DefaultLength2,
|
||||||
|
@ -1054,6 +1056,7 @@ func (engine *Engine) mapType(parsingTables map[reflect.Type]*core.Table, v refl
|
||||||
idFieldColName = col.Name
|
idFieldColName = col.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
col.FieldType = t.Field(i).Type
|
||||||
ctx.col = col
|
ctx.col = col
|
||||||
}
|
}
|
||||||
if col.IsAutoIncrement {
|
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
|
// NoCascade indicate that no cascade load child object
|
||||||
func (session *Session) NoCascade() *Session {
|
func (session *Session) NoCascade() *Session {
|
||||||
session.statement.cascadeMode = cascadeManuallyLoad
|
session.statement.cascadeMode = cascadeManually
|
||||||
return session
|
return session
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,12 +204,12 @@ func (session *Session) Charset(charset string) *Session {
|
||||||
|
|
||||||
// Cascade indicates if loading sub Struct
|
// Cascade indicates if loading sub Struct
|
||||||
func (session *Session) Cascade(trueOrFalse ...bool) *Session {
|
func (session *Session) Cascade(trueOrFalse ...bool) *Session {
|
||||||
var mode = cascadeAutoLoad
|
var mode = cascadeAuto
|
||||||
if len(trueOrFalse) >= 1 {
|
if len(trueOrFalse) >= 1 {
|
||||||
if trueOrFalse[0] {
|
if trueOrFalse[0] {
|
||||||
mode = cascadeAutoLoad
|
mode = cascadeAuto
|
||||||
} else {
|
} else {
|
||||||
mode = cascadeManuallyLoad
|
mode = cascadeManually
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,8 +447,8 @@ func (session *Session) slice2Bean(scanResults []interface{}, fields []string, b
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
rawValueType := reflect.TypeOf(rawValue.Interface())
|
|
||||||
vv := reflect.ValueOf(rawValue.Interface())
|
vv := reflect.ValueOf(rawValue.Interface())
|
||||||
|
rawValueType := vv.Type()
|
||||||
col := table.GetColumnIdx(key, idx)
|
col := table.GetColumnIdx(key, idx)
|
||||||
if col.IsPrimaryKey {
|
if col.IsPrimaryKey {
|
||||||
pk = append(pk, rawValue.Interface())
|
pk = append(pk, rawValue.Interface())
|
||||||
|
@ -639,35 +639,25 @@ func (session *Session) slice2Bean(scanResults []interface{}, fields []string, b
|
||||||
} else if (col.AssociateType == core.AssociateNone &&
|
} else if (col.AssociateType == core.AssociateNone &&
|
||||||
session.statement.cascadeMode == cascadeCompitable) ||
|
session.statement.cascadeMode == cascadeCompitable) ||
|
||||||
(col.AssociateType == core.AssociateBelongsTo &&
|
(col.AssociateType == core.AssociateBelongsTo &&
|
||||||
session.statement.cascadeMode == cascadeAutoLoad) {
|
session.statement.cascadeMode == cascadeAuto) {
|
||||||
table := col.AssociateTable
|
var pk = make(core.PK, len(col.AssociateTable.PrimaryKeys))
|
||||||
|
|
||||||
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))
|
|
||||||
var err error
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isPKZero(pk) {
|
pk[0] = reflect.ValueOf(pk[0]).Elem().Interface()
|
||||||
// !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
|
if err = session.getByPK(pk, fieldValue); err != nil {
|
||||||
// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
|
return nil, err
|
||||||
// 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")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
hasAssigned = true
|
||||||
} else if col.AssociateType == core.AssociateBelongsTo {
|
} else if col.AssociateType == core.AssociateBelongsTo {
|
||||||
hasAssigned = true
|
hasAssigned = true
|
||||||
err := convertAssign(fieldValue.FieldByName(table.PKColumns()[0].FieldName).Addr().Interface(),
|
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 &&
|
if (col.AssociateType == core.AssociateNone &&
|
||||||
session.statement.cascadeMode == cascadeCompitable) ||
|
session.statement.cascadeMode == cascadeCompitable) ||
|
||||||
(col.AssociateType == core.AssociateBelongsTo &&
|
(col.AssociateType == core.AssociateBelongsTo &&
|
||||||
session.statement.cascadeMode == cascadeAutoLoad) {
|
session.statement.cascadeMode == cascadeAuto) {
|
||||||
table := col.AssociateTable
|
var pk = make(core.PK, len(col.AssociateTable.PrimaryKeys))
|
||||||
|
|
||||||
hasAssigned = true
|
|
||||||
if len(table.PrimaryKeys) != 1 {
|
|
||||||
panic("unsupported non or composited primary key cascade")
|
|
||||||
}
|
|
||||||
var pk = make(core.PK, len(table.PrimaryKeys))
|
|
||||||
var err error
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isPKZero(pk) {
|
pk[0] = reflect.ValueOf(pk[0]).Elem().Interface()
|
||||||
// !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
|
if err = session.getByPK(pk, fieldValue); err != nil {
|
||||||
// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
|
return nil, err
|
||||||
// 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")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
hasAssigned = true
|
||||||
} else if col.AssociateType == core.AssociateBelongsTo {
|
} else if col.AssociateType == core.AssociateBelongsTo {
|
||||||
hasAssigned = true
|
hasAssigned = true
|
||||||
if fieldValue.IsNil() {
|
if fieldValue.IsNil() {
|
||||||
|
@ -873,6 +841,34 @@ func (session *Session) slice2Bean(scanResults []interface{}, fields []string, b
|
||||||
return pk, nil
|
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
|
// saveLastSQL stores executed query information
|
||||||
func (session *Session) saveLastSQL(sql string, args ...interface{}) {
|
func (session *Session) saveLastSQL(sql string, args ...interface{}) {
|
||||||
session.lastSQL = sql
|
session.lastSQL = sql
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"database/sql/driver"
|
"database/sql/driver"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -206,37 +205,18 @@ func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value,
|
||||||
} else if (col.AssociateType == core.AssociateNone &&
|
} else if (col.AssociateType == core.AssociateNone &&
|
||||||
session.statement.cascadeMode == cascadeCompitable) ||
|
session.statement.cascadeMode == cascadeCompitable) ||
|
||||||
(col.AssociateType == core.AssociateBelongsTo &&
|
(col.AssociateType == core.AssociateBelongsTo &&
|
||||||
session.statement.cascadeMode == cascadeAutoLoad) {
|
session.statement.cascadeMode == cascadeAuto) {
|
||||||
table := col.AssociateTable
|
var pk = make(core.PK, len(col.AssociateTable.PrimaryKeys))
|
||||||
|
// only 1 PK checked on tag parsing
|
||||||
// TODO: current only support 1 primary key
|
rawValueType := col.AssociateTable.ColumnType(col.AssociateTable.PKColumns()[0].FieldName)
|
||||||
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)
|
|
||||||
var err error
|
var err error
|
||||||
pk[0], err = str2PK(string(data), rawValueType)
|
pk[0], err = str2PK(string(data), rawValueType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isPKZero(pk) {
|
if err = session.getByPK(pk, fieldValue); err != nil {
|
||||||
// !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
|
return err
|
||||||
// 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")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -489,35 +469,18 @@ func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value,
|
||||||
if (col.AssociateType == core.AssociateNone &&
|
if (col.AssociateType == core.AssociateNone &&
|
||||||
session.statement.cascadeMode == cascadeCompitable) ||
|
session.statement.cascadeMode == cascadeCompitable) ||
|
||||||
(col.AssociateType == core.AssociateBelongsTo &&
|
(col.AssociateType == core.AssociateBelongsTo &&
|
||||||
session.statement.cascadeMode == cascadeAutoLoad) {
|
session.statement.cascadeMode == cascadeAuto) {
|
||||||
table := col.AssociateTable
|
var pk = make(core.PK, len(col.AssociateTable.PrimaryKeys))
|
||||||
if len(table.PrimaryKeys) > 1 {
|
|
||||||
return errors.New("unsupported composited primary key cascade")
|
|
||||||
}
|
|
||||||
|
|
||||||
var pk = make(core.PK, len(table.PrimaryKeys))
|
|
||||||
var err error
|
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)
|
pk[0], err = str2PK(string(data), rawValueType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isPKZero(pk) {
|
if err = session.getByPK(pk, fieldValue); err != nil {
|
||||||
structInter := reflect.New(fieldType.Elem())
|
return err
|
||||||
// !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")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,9 +172,8 @@ func (session *Session) noCacheFind(table *core.Table, containerValue reflect.Va
|
||||||
|
|
||||||
var newElemFunc func(fields []string) reflect.Value
|
var newElemFunc func(fields []string) reflect.Value
|
||||||
elemType := containerValue.Type().Elem()
|
elemType := containerValue.Type().Elem()
|
||||||
var isPointer bool
|
var isPointer = elemType.Kind() == reflect.Ptr
|
||||||
if elemType.Kind() == reflect.Ptr {
|
if isPointer {
|
||||||
isPointer = true
|
|
||||||
elemType = elemType.Elem()
|
elemType = elemType.Elem()
|
||||||
}
|
}
|
||||||
if elemType.Kind() == reflect.Ptr {
|
if elemType.Kind() == reflect.Ptr {
|
||||||
|
|
|
@ -37,8 +37,8 @@ type cascadeMode int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
cascadeCompitable cascadeMode = iota
|
cascadeCompitable cascadeMode = iota
|
||||||
cascadeAutoLoad
|
cascadeAuto
|
||||||
cascadeManuallyLoad
|
cascadeManually
|
||||||
)
|
)
|
||||||
|
|
||||||
// Statement save all the sql info for executing SQL
|
// Statement save all the sql info for executing SQL
|
||||||
|
|
Loading…
Reference in New Issue