mirror of https://github.com/go-gorm/gorm.git
Add association Delete support
This commit is contained in:
parent
922a8efc53
commit
20cb57b1ac
|
@ -2,9 +2,11 @@ package gorm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
"github.com/jinzhu/gorm/clause"
|
"github.com/jinzhu/gorm/clause"
|
||||||
"github.com/jinzhu/gorm/schema"
|
"github.com/jinzhu/gorm/schema"
|
||||||
|
"github.com/jinzhu/gorm/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Association Mode contains some helper methods to handle relationship things easily.
|
// Association Mode contains some helper methods to handle relationship things easily.
|
||||||
|
@ -46,6 +48,90 @@ func (association *Association) Replace(values ...interface{}) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (association *Association) Delete(values ...interface{}) error {
|
func (association *Association) Delete(values ...interface{}) error {
|
||||||
|
if association.Error == nil {
|
||||||
|
var (
|
||||||
|
tx = association.DB
|
||||||
|
rel = association.Relationship
|
||||||
|
reflectValue = tx.Statement.ReflectValue
|
||||||
|
conds = rel.ToQueryConditions(reflectValue)
|
||||||
|
relFields []*schema.Field
|
||||||
|
foreignKeys []string
|
||||||
|
updateAttrs = map[string]interface{}{}
|
||||||
|
)
|
||||||
|
|
||||||
|
for _, ref := range rel.References {
|
||||||
|
if ref.PrimaryValue == "" {
|
||||||
|
if rel.JoinTable == nil || !ref.OwnPrimaryKey {
|
||||||
|
if ref.OwnPrimaryKey {
|
||||||
|
relFields = append(relFields, ref.ForeignKey)
|
||||||
|
} else {
|
||||||
|
relFields = append(relFields, ref.PrimaryKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
foreignKeys = append(foreignKeys, ref.ForeignKey.DBName)
|
||||||
|
updateAttrs[ref.ForeignKey.DBName] = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
relValuesMap, relQueryValues := schema.GetIdentityFieldValuesMapFromValues(values, relFields)
|
||||||
|
column, values := schema.ToQueryValues(foreignKeys, relQueryValues)
|
||||||
|
tx.Where(clause.IN{Column: column, Values: values})
|
||||||
|
|
||||||
|
switch association.Relationship.Type {
|
||||||
|
case schema.HasOne, schema.HasMany:
|
||||||
|
modelValue := reflect.New(rel.FieldSchema.ModelType).Interface()
|
||||||
|
tx.Model(modelValue).Clauses(clause.Where{Exprs: conds}).UpdateColumns(updateAttrs)
|
||||||
|
case schema.BelongsTo:
|
||||||
|
tx.Clauses(clause.Where{Exprs: conds}).UpdateColumns(updateAttrs)
|
||||||
|
case schema.Many2Many:
|
||||||
|
modelValue := reflect.New(rel.JoinTable.ModelType).Interface()
|
||||||
|
tx.Clauses(clause.Where{Exprs: conds}).Delete(modelValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tx.Error == nil {
|
||||||
|
cleanUpDeletedRelations := func(data reflect.Value) {
|
||||||
|
if _, zero := rel.Field.ValueOf(data); !zero {
|
||||||
|
fieldValue := reflect.Indirect(rel.Field.ReflectValueOf(data))
|
||||||
|
|
||||||
|
fieldValues := make([]reflect.Value, len(relFields))
|
||||||
|
switch fieldValue.Kind() {
|
||||||
|
case reflect.Slice, reflect.Array:
|
||||||
|
validFieldValues := reflect.Zero(rel.Field.FieldType)
|
||||||
|
for i := 0; i < fieldValue.Len(); i++ {
|
||||||
|
for idx, field := range relFields {
|
||||||
|
fieldValues[idx] = field.ReflectValueOf(fieldValue.Index(i))
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := relValuesMap[utils.ToStringKey(fieldValues...)]; !ok {
|
||||||
|
validFieldValues = reflect.Append(validFieldValues, fieldValue.Index(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rel.Field.Set(data, validFieldValues)
|
||||||
|
case reflect.Struct:
|
||||||
|
for idx, field := range relFields {
|
||||||
|
fieldValues[idx] = field.ReflectValueOf(data)
|
||||||
|
}
|
||||||
|
if _, ok := relValuesMap[utils.ToStringKey(fieldValues...)]; ok {
|
||||||
|
rel.Field.Set(data, reflect.Zero(rel.FieldSchema.ModelType))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch reflectValue.Kind() {
|
||||||
|
case reflect.Slice, reflect.Array:
|
||||||
|
for i := 0; i < reflectValue.Len(); i++ {
|
||||||
|
cleanUpDeletedRelations(reflect.Indirect(reflectValue.Index(i)))
|
||||||
|
}
|
||||||
|
case reflect.Struct:
|
||||||
|
cleanUpDeletedRelations(reflectValue)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
association.Error = tx.Error
|
||||||
|
}
|
||||||
|
}
|
||||||
return association.Error
|
return association.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,6 +147,10 @@ func (association *Association) Count() (count int) {
|
||||||
)
|
)
|
||||||
|
|
||||||
if association.Relationship.JoinTable != nil {
|
if association.Relationship.JoinTable != nil {
|
||||||
|
for _, queryClause := range association.Relationship.JoinTable.QueryClauses {
|
||||||
|
tx.Clauses(queryClause)
|
||||||
|
}
|
||||||
|
|
||||||
tx.Clauses(clause.From{Joins: []clause.Join{{
|
tx.Clauses(clause.From{Joins: []clause.Join{{
|
||||||
Table: clause.Table{Name: association.Relationship.JoinTable.Table},
|
Table: clause.Table{Name: association.Relationship.JoinTable.Table},
|
||||||
ON: clause.Where{Exprs: conds},
|
ON: clause.Where{Exprs: conds},
|
||||||
|
|
|
@ -128,6 +128,21 @@ func GetIdentityFieldValuesMap(reflectValue reflect.Value, fields []*Field) (map
|
||||||
return dataResults, results
|
return dataResults, results
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetIdentityFieldValuesMapFromValues get identity map from fields
|
||||||
|
func GetIdentityFieldValuesMapFromValues(values []interface{}, fields []*Field) (map[string][]reflect.Value, [][]interface{}) {
|
||||||
|
resultsMap := map[string][]reflect.Value{}
|
||||||
|
results := [][]interface{}{}
|
||||||
|
|
||||||
|
for _, v := range values {
|
||||||
|
rm, rs := GetIdentityFieldValuesMap(reflect.Indirect(reflect.ValueOf(v)), fields)
|
||||||
|
for k, v := range rm {
|
||||||
|
resultsMap[k] = append(resultsMap[k], v...)
|
||||||
|
}
|
||||||
|
results = append(results, rs...)
|
||||||
|
}
|
||||||
|
return resultsMap, results
|
||||||
|
}
|
||||||
|
|
||||||
// ToQueryValues to query values
|
// ToQueryValues to query values
|
||||||
func ToQueryValues(foreignKeys []string, foreignValues [][]interface{}) (interface{}, []interface{}) {
|
func ToQueryValues(foreignKeys []string, foreignValues [][]interface{}) (interface{}, []interface{}) {
|
||||||
queryValues := make([]interface{}, len(foreignValues))
|
queryValues := make([]interface{}, len(foreignValues))
|
||||||
|
|
Loading…
Reference in New Issue