association.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  1. package gorm
  2. import (
  3. "fmt"
  4. "reflect"
  5. "strings"
  6. "gorm.io/gorm/clause"
  7. "gorm.io/gorm/schema"
  8. "gorm.io/gorm/utils"
  9. )
  10. // Association Mode contains some helper methods to handle relationship things easily.
  11. type Association struct {
  12. DB *DB
  13. Relationship *schema.Relationship
  14. Unscope bool
  15. Error error
  16. }
  17. func (db *DB) Association(column string) *Association {
  18. association := &Association{DB: db}
  19. table := db.Statement.Table
  20. if err := db.Statement.Parse(db.Statement.Model); err == nil {
  21. db.Statement.Table = table
  22. association.Relationship = db.Statement.Schema.Relationships.Relations[column]
  23. if association.Relationship == nil {
  24. association.Error = fmt.Errorf("%w: %s", ErrUnsupportedRelation, column)
  25. }
  26. db.Statement.ReflectValue = reflect.ValueOf(db.Statement.Model)
  27. for db.Statement.ReflectValue.Kind() == reflect.Ptr {
  28. db.Statement.ReflectValue = db.Statement.ReflectValue.Elem()
  29. }
  30. } else {
  31. association.Error = err
  32. }
  33. return association
  34. }
  35. func (association *Association) Unscoped() *Association {
  36. return &Association{
  37. DB: association.DB,
  38. Relationship: association.Relationship,
  39. Error: association.Error,
  40. Unscope: true,
  41. }
  42. }
  43. func (association *Association) Find(out interface{}, conds ...interface{}) error {
  44. if association.Error == nil {
  45. association.Error = association.buildCondition().Find(out, conds...).Error
  46. }
  47. return association.Error
  48. }
  49. func (association *Association) Append(values ...interface{}) error {
  50. if association.Error == nil {
  51. switch association.Relationship.Type {
  52. case schema.HasOne, schema.BelongsTo:
  53. if len(values) > 0 {
  54. association.Error = association.Replace(values...)
  55. }
  56. default:
  57. association.saveAssociation( /*clear*/ false, values...)
  58. }
  59. }
  60. return association.Error
  61. }
  62. func (association *Association) Replace(values ...interface{}) error {
  63. if association.Error == nil {
  64. reflectValue := association.DB.Statement.ReflectValue
  65. rel := association.Relationship
  66. var oldBelongsToExpr clause.Expression
  67. // we have to record the old BelongsTo value
  68. if association.Unscope && rel.Type == schema.BelongsTo {
  69. var foreignFields []*schema.Field
  70. for _, ref := range rel.References {
  71. if !ref.OwnPrimaryKey {
  72. foreignFields = append(foreignFields, ref.ForeignKey)
  73. }
  74. }
  75. if _, fvs := schema.GetIdentityFieldValuesMap(association.DB.Statement.Context, reflectValue, foreignFields); len(fvs) > 0 {
  76. column, values := schema.ToQueryValues(rel.FieldSchema.Table, rel.FieldSchema.PrimaryFieldDBNames, fvs)
  77. oldBelongsToExpr = clause.IN{Column: column, Values: values}
  78. }
  79. }
  80. // save associations
  81. if association.saveAssociation( /*clear*/ true, values...); association.Error != nil {
  82. return association.Error
  83. }
  84. // set old associations's foreign key to null
  85. switch rel.Type {
  86. case schema.BelongsTo:
  87. if len(values) == 0 {
  88. updateMap := map[string]interface{}{}
  89. switch reflectValue.Kind() {
  90. case reflect.Slice, reflect.Array:
  91. for i := 0; i < reflectValue.Len(); i++ {
  92. association.Error = rel.Field.Set(association.DB.Statement.Context, reflectValue.Index(i), reflect.Zero(rel.Field.FieldType).Interface())
  93. }
  94. case reflect.Struct:
  95. association.Error = rel.Field.Set(association.DB.Statement.Context, reflectValue, reflect.Zero(rel.Field.FieldType).Interface())
  96. }
  97. for _, ref := range rel.References {
  98. updateMap[ref.ForeignKey.DBName] = nil
  99. }
  100. association.Error = association.DB.UpdateColumns(updateMap).Error
  101. }
  102. if association.Unscope && oldBelongsToExpr != nil {
  103. association.Error = association.DB.Model(nil).Where(oldBelongsToExpr).Delete(reflect.New(rel.FieldSchema.ModelType).Interface()).Error
  104. }
  105. case schema.HasOne, schema.HasMany:
  106. var (
  107. primaryFields []*schema.Field
  108. foreignKeys []string
  109. updateMap = map[string]interface{}{}
  110. relValues = schema.GetRelationsValues(association.DB.Statement.Context, reflectValue, []*schema.Relationship{rel})
  111. modelValue = reflect.New(rel.FieldSchema.ModelType).Interface()
  112. tx = association.DB.Model(modelValue)
  113. )
  114. if _, rvs := schema.GetIdentityFieldValuesMap(association.DB.Statement.Context, relValues, rel.FieldSchema.PrimaryFields); len(rvs) > 0 {
  115. if column, values := schema.ToQueryValues(rel.FieldSchema.Table, rel.FieldSchema.PrimaryFieldDBNames, rvs); len(values) > 0 {
  116. tx.Not(clause.IN{Column: column, Values: values})
  117. }
  118. }
  119. for _, ref := range rel.References {
  120. if ref.OwnPrimaryKey {
  121. primaryFields = append(primaryFields, ref.PrimaryKey)
  122. foreignKeys = append(foreignKeys, ref.ForeignKey.DBName)
  123. updateMap[ref.ForeignKey.DBName] = nil
  124. } else if ref.PrimaryValue != "" {
  125. tx.Where(clause.Eq{Column: ref.ForeignKey.DBName, Value: ref.PrimaryValue})
  126. }
  127. }
  128. if _, pvs := schema.GetIdentityFieldValuesMap(association.DB.Statement.Context, reflectValue, primaryFields); len(pvs) > 0 {
  129. column, values := schema.ToQueryValues(rel.FieldSchema.Table, foreignKeys, pvs)
  130. if association.Unscope {
  131. association.Error = tx.Where(clause.IN{Column: column, Values: values}).Delete(modelValue).Error
  132. } else {
  133. association.Error = tx.Where(clause.IN{Column: column, Values: values}).UpdateColumns(updateMap).Error
  134. }
  135. }
  136. case schema.Many2Many:
  137. var (
  138. primaryFields, relPrimaryFields []*schema.Field
  139. joinPrimaryKeys, joinRelPrimaryKeys []string
  140. modelValue = reflect.New(rel.JoinTable.ModelType).Interface()
  141. tx = association.DB.Model(modelValue)
  142. )
  143. for _, ref := range rel.References {
  144. if ref.PrimaryValue == "" {
  145. if ref.OwnPrimaryKey {
  146. primaryFields = append(primaryFields, ref.PrimaryKey)
  147. joinPrimaryKeys = append(joinPrimaryKeys, ref.ForeignKey.DBName)
  148. } else {
  149. relPrimaryFields = append(relPrimaryFields, ref.PrimaryKey)
  150. joinRelPrimaryKeys = append(joinRelPrimaryKeys, ref.ForeignKey.DBName)
  151. }
  152. } else {
  153. tx.Clauses(clause.Eq{Column: ref.ForeignKey.DBName, Value: ref.PrimaryValue})
  154. }
  155. }
  156. _, pvs := schema.GetIdentityFieldValuesMap(association.DB.Statement.Context, reflectValue, primaryFields)
  157. if column, values := schema.ToQueryValues(rel.JoinTable.Table, joinPrimaryKeys, pvs); len(values) > 0 {
  158. tx.Where(clause.IN{Column: column, Values: values})
  159. } else {
  160. return ErrPrimaryKeyRequired
  161. }
  162. _, rvs := schema.GetIdentityFieldValuesMapFromValues(association.DB.Statement.Context, values, relPrimaryFields)
  163. if relColumn, relValues := schema.ToQueryValues(rel.JoinTable.Table, joinRelPrimaryKeys, rvs); len(relValues) > 0 {
  164. tx.Where(clause.Not(clause.IN{Column: relColumn, Values: relValues}))
  165. }
  166. association.Error = tx.Delete(modelValue).Error
  167. }
  168. }
  169. return association.Error
  170. }
  171. func (association *Association) Delete(values ...interface{}) error {
  172. if association.Error == nil {
  173. var (
  174. reflectValue = association.DB.Statement.ReflectValue
  175. rel = association.Relationship
  176. primaryFields []*schema.Field
  177. foreignKeys []string
  178. updateAttrs = map[string]interface{}{}
  179. conds []clause.Expression
  180. )
  181. for _, ref := range rel.References {
  182. if ref.PrimaryValue == "" {
  183. primaryFields = append(primaryFields, ref.PrimaryKey)
  184. foreignKeys = append(foreignKeys, ref.ForeignKey.DBName)
  185. updateAttrs[ref.ForeignKey.DBName] = nil
  186. } else {
  187. conds = append(conds, clause.Eq{Column: ref.ForeignKey.DBName, Value: ref.PrimaryValue})
  188. }
  189. }
  190. switch rel.Type {
  191. case schema.BelongsTo:
  192. associationDB := association.DB.Session(&Session{})
  193. tx := associationDB.Model(reflect.New(rel.Schema.ModelType).Interface())
  194. _, pvs := schema.GetIdentityFieldValuesMap(association.DB.Statement.Context, reflectValue, rel.Schema.PrimaryFields)
  195. if pcolumn, pvalues := schema.ToQueryValues(rel.Schema.Table, rel.Schema.PrimaryFieldDBNames, pvs); len(pvalues) > 0 {
  196. conds = append(conds, clause.IN{Column: pcolumn, Values: pvalues})
  197. } else {
  198. return ErrPrimaryKeyRequired
  199. }
  200. _, rvs := schema.GetIdentityFieldValuesMapFromValues(association.DB.Statement.Context, values, primaryFields)
  201. relColumn, relValues := schema.ToQueryValues(rel.Schema.Table, foreignKeys, rvs)
  202. conds = append(conds, clause.IN{Column: relColumn, Values: relValues})
  203. association.Error = tx.Clauses(conds...).UpdateColumns(updateAttrs).Error
  204. if association.Unscope {
  205. var foreignFields []*schema.Field
  206. for _, ref := range rel.References {
  207. if !ref.OwnPrimaryKey {
  208. foreignFields = append(foreignFields, ref.ForeignKey)
  209. }
  210. }
  211. if _, fvs := schema.GetIdentityFieldValuesMap(association.DB.Statement.Context, reflectValue, foreignFields); len(fvs) > 0 {
  212. column, values := schema.ToQueryValues(rel.FieldSchema.Table, rel.FieldSchema.PrimaryFieldDBNames, fvs)
  213. association.Error = associationDB.Model(nil).Where(clause.IN{Column: column, Values: values}).Delete(reflect.New(rel.FieldSchema.ModelType).Interface()).Error
  214. }
  215. }
  216. case schema.HasOne, schema.HasMany:
  217. model := reflect.New(rel.FieldSchema.ModelType).Interface()
  218. tx := association.DB.Model(model)
  219. _, pvs := schema.GetIdentityFieldValuesMap(association.DB.Statement.Context, reflectValue, primaryFields)
  220. if pcolumn, pvalues := schema.ToQueryValues(rel.FieldSchema.Table, foreignKeys, pvs); len(pvalues) > 0 {
  221. conds = append(conds, clause.IN{Column: pcolumn, Values: pvalues})
  222. } else {
  223. return ErrPrimaryKeyRequired
  224. }
  225. _, rvs := schema.GetIdentityFieldValuesMapFromValues(association.DB.Statement.Context, values, rel.FieldSchema.PrimaryFields)
  226. relColumn, relValues := schema.ToQueryValues(rel.FieldSchema.Table, rel.FieldSchema.PrimaryFieldDBNames, rvs)
  227. conds = append(conds, clause.IN{Column: relColumn, Values: relValues})
  228. if association.Unscope {
  229. association.Error = tx.Clauses(conds...).Delete(model).Error
  230. } else {
  231. association.Error = tx.Clauses(conds...).UpdateColumns(updateAttrs).Error
  232. }
  233. case schema.Many2Many:
  234. var (
  235. primaryFields, relPrimaryFields []*schema.Field
  236. joinPrimaryKeys, joinRelPrimaryKeys []string
  237. joinValue = reflect.New(rel.JoinTable.ModelType).Interface()
  238. )
  239. for _, ref := range rel.References {
  240. if ref.PrimaryValue == "" {
  241. if ref.OwnPrimaryKey {
  242. primaryFields = append(primaryFields, ref.PrimaryKey)
  243. joinPrimaryKeys = append(joinPrimaryKeys, ref.ForeignKey.DBName)
  244. } else {
  245. relPrimaryFields = append(relPrimaryFields, ref.PrimaryKey)
  246. joinRelPrimaryKeys = append(joinRelPrimaryKeys, ref.ForeignKey.DBName)
  247. }
  248. } else {
  249. conds = append(conds, clause.Eq{Column: ref.ForeignKey.DBName, Value: ref.PrimaryValue})
  250. }
  251. }
  252. _, pvs := schema.GetIdentityFieldValuesMap(association.DB.Statement.Context, reflectValue, primaryFields)
  253. if pcolumn, pvalues := schema.ToQueryValues(rel.JoinTable.Table, joinPrimaryKeys, pvs); len(pvalues) > 0 {
  254. conds = append(conds, clause.IN{Column: pcolumn, Values: pvalues})
  255. } else {
  256. return ErrPrimaryKeyRequired
  257. }
  258. _, rvs := schema.GetIdentityFieldValuesMapFromValues(association.DB.Statement.Context, values, relPrimaryFields)
  259. relColumn, relValues := schema.ToQueryValues(rel.JoinTable.Table, joinRelPrimaryKeys, rvs)
  260. conds = append(conds, clause.IN{Column: relColumn, Values: relValues})
  261. association.Error = association.DB.Where(clause.Where{Exprs: conds}).Model(nil).Delete(joinValue).Error
  262. }
  263. if association.Error == nil {
  264. // clean up deleted values's foreign key
  265. relValuesMap, _ := schema.GetIdentityFieldValuesMapFromValues(association.DB.Statement.Context, values, rel.FieldSchema.PrimaryFields)
  266. cleanUpDeletedRelations := func(data reflect.Value) {
  267. if _, zero := rel.Field.ValueOf(association.DB.Statement.Context, data); !zero {
  268. fieldValue := reflect.Indirect(rel.Field.ReflectValueOf(association.DB.Statement.Context, data))
  269. primaryValues := make([]interface{}, len(rel.FieldSchema.PrimaryFields))
  270. switch fieldValue.Kind() {
  271. case reflect.Slice, reflect.Array:
  272. validFieldValues := reflect.Zero(rel.Field.IndirectFieldType)
  273. for i := 0; i < fieldValue.Len(); i++ {
  274. for idx, field := range rel.FieldSchema.PrimaryFields {
  275. primaryValues[idx], _ = field.ValueOf(association.DB.Statement.Context, fieldValue.Index(i))
  276. }
  277. if _, ok := relValuesMap[utils.ToStringKey(primaryValues...)]; !ok {
  278. validFieldValues = reflect.Append(validFieldValues, fieldValue.Index(i))
  279. }
  280. }
  281. association.Error = rel.Field.Set(association.DB.Statement.Context, data, validFieldValues.Interface())
  282. case reflect.Struct:
  283. for idx, field := range rel.FieldSchema.PrimaryFields {
  284. primaryValues[idx], _ = field.ValueOf(association.DB.Statement.Context, fieldValue)
  285. }
  286. if _, ok := relValuesMap[utils.ToStringKey(primaryValues...)]; ok {
  287. if association.Error = rel.Field.Set(association.DB.Statement.Context, data, reflect.Zero(rel.FieldSchema.ModelType).Interface()); association.Error != nil {
  288. break
  289. }
  290. if rel.JoinTable == nil {
  291. for _, ref := range rel.References {
  292. if ref.OwnPrimaryKey || ref.PrimaryValue != "" {
  293. association.Error = ref.ForeignKey.Set(association.DB.Statement.Context, fieldValue, reflect.Zero(ref.ForeignKey.FieldType).Interface())
  294. } else {
  295. association.Error = ref.ForeignKey.Set(association.DB.Statement.Context, data, reflect.Zero(ref.ForeignKey.FieldType).Interface())
  296. }
  297. }
  298. }
  299. }
  300. }
  301. }
  302. }
  303. switch reflectValue.Kind() {
  304. case reflect.Slice, reflect.Array:
  305. for i := 0; i < reflectValue.Len(); i++ {
  306. cleanUpDeletedRelations(reflect.Indirect(reflectValue.Index(i)))
  307. }
  308. case reflect.Struct:
  309. cleanUpDeletedRelations(reflectValue)
  310. }
  311. }
  312. }
  313. return association.Error
  314. }
  315. func (association *Association) Clear() error {
  316. return association.Replace()
  317. }
  318. func (association *Association) Count() (count int64) {
  319. if association.Error == nil {
  320. association.Error = association.buildCondition().Count(&count).Error
  321. }
  322. return
  323. }
  324. type assignBack struct {
  325. Source reflect.Value
  326. Index int
  327. Dest reflect.Value
  328. }
  329. func (association *Association) saveAssociation(clear bool, values ...interface{}) {
  330. var (
  331. reflectValue = association.DB.Statement.ReflectValue
  332. assignBacks []assignBack // assign association values back to arguments after save
  333. )
  334. appendToRelations := func(source, rv reflect.Value, clear bool) {
  335. switch association.Relationship.Type {
  336. case schema.HasOne, schema.BelongsTo:
  337. switch rv.Kind() {
  338. case reflect.Slice, reflect.Array:
  339. if rv.Len() > 0 {
  340. association.Error = association.Relationship.Field.Set(association.DB.Statement.Context, source, rv.Index(0).Addr().Interface())
  341. if association.Relationship.Field.FieldType.Kind() == reflect.Struct {
  342. assignBacks = append(assignBacks, assignBack{Source: source, Dest: rv.Index(0)})
  343. }
  344. }
  345. case reflect.Struct:
  346. if !rv.CanAddr() {
  347. association.Error = ErrInvalidValue
  348. return
  349. }
  350. association.Error = association.Relationship.Field.Set(association.DB.Statement.Context, source, rv.Addr().Interface())
  351. if association.Relationship.Field.FieldType.Kind() == reflect.Struct {
  352. assignBacks = append(assignBacks, assignBack{Source: source, Dest: rv})
  353. }
  354. }
  355. case schema.HasMany, schema.Many2Many:
  356. elemType := association.Relationship.Field.IndirectFieldType.Elem()
  357. oldFieldValue := reflect.Indirect(association.Relationship.Field.ReflectValueOf(association.DB.Statement.Context, source))
  358. var fieldValue reflect.Value
  359. if clear {
  360. fieldValue = reflect.MakeSlice(oldFieldValue.Type(), 0, oldFieldValue.Cap())
  361. } else {
  362. fieldValue = reflect.MakeSlice(oldFieldValue.Type(), oldFieldValue.Len(), oldFieldValue.Cap())
  363. reflect.Copy(fieldValue, oldFieldValue)
  364. }
  365. appendToFieldValues := func(ev reflect.Value) {
  366. if ev.Type().AssignableTo(elemType) {
  367. fieldValue = reflect.Append(fieldValue, ev)
  368. } else if ev.Type().Elem().AssignableTo(elemType) {
  369. fieldValue = reflect.Append(fieldValue, ev.Elem())
  370. } else {
  371. association.Error = fmt.Errorf("unsupported data type: %v for relation %s", ev.Type(), association.Relationship.Name)
  372. }
  373. if elemType.Kind() == reflect.Struct {
  374. assignBacks = append(assignBacks, assignBack{Source: source, Dest: ev, Index: fieldValue.Len()})
  375. }
  376. }
  377. switch rv.Kind() {
  378. case reflect.Slice, reflect.Array:
  379. for i := 0; i < rv.Len(); i++ {
  380. appendToFieldValues(reflect.Indirect(rv.Index(i)).Addr())
  381. }
  382. case reflect.Struct:
  383. if !rv.CanAddr() {
  384. association.Error = ErrInvalidValue
  385. return
  386. }
  387. appendToFieldValues(rv.Addr())
  388. }
  389. if association.Error == nil {
  390. association.Error = association.Relationship.Field.Set(association.DB.Statement.Context, source, fieldValue.Interface())
  391. }
  392. }
  393. }
  394. selectedSaveColumns := []string{association.Relationship.Name}
  395. omitColumns := []string{}
  396. selectColumns, _ := association.DB.Statement.SelectAndOmitColumns(true, false)
  397. for name, ok := range selectColumns {
  398. columnName := ""
  399. if strings.HasPrefix(name, association.Relationship.Name) {
  400. if columnName = strings.TrimPrefix(name, association.Relationship.Name); columnName == ".*" {
  401. columnName = name
  402. }
  403. } else if strings.HasPrefix(name, clause.Associations) {
  404. columnName = name
  405. }
  406. if columnName != "" {
  407. if ok {
  408. selectedSaveColumns = append(selectedSaveColumns, columnName)
  409. } else {
  410. omitColumns = append(omitColumns, columnName)
  411. }
  412. }
  413. }
  414. for _, ref := range association.Relationship.References {
  415. if !ref.OwnPrimaryKey {
  416. selectedSaveColumns = append(selectedSaveColumns, ref.ForeignKey.Name)
  417. }
  418. }
  419. associationDB := association.DB.Session(&Session{}).Model(nil)
  420. if !association.DB.FullSaveAssociations {
  421. associationDB.Select(selectedSaveColumns)
  422. }
  423. if len(omitColumns) > 0 {
  424. associationDB.Omit(omitColumns...)
  425. }
  426. associationDB = associationDB.Session(&Session{})
  427. switch reflectValue.Kind() {
  428. case reflect.Slice, reflect.Array:
  429. if len(values) != reflectValue.Len() {
  430. // clear old data
  431. if clear && len(values) == 0 {
  432. for i := 0; i < reflectValue.Len(); i++ {
  433. if err := association.Relationship.Field.Set(association.DB.Statement.Context, reflectValue.Index(i), reflect.New(association.Relationship.Field.IndirectFieldType).Interface()); err != nil {
  434. association.Error = err
  435. break
  436. }
  437. if association.Relationship.JoinTable == nil {
  438. for _, ref := range association.Relationship.References {
  439. if !ref.OwnPrimaryKey && ref.PrimaryValue == "" {
  440. if err := ref.ForeignKey.Set(association.DB.Statement.Context, reflectValue.Index(i), reflect.Zero(ref.ForeignKey.FieldType).Interface()); err != nil {
  441. association.Error = err
  442. break
  443. }
  444. }
  445. }
  446. }
  447. }
  448. break
  449. }
  450. association.Error = ErrInvalidValueOfLength
  451. return
  452. }
  453. for i := 0; i < reflectValue.Len(); i++ {
  454. appendToRelations(reflectValue.Index(i), reflect.Indirect(reflect.ValueOf(values[i])), clear)
  455. if association.Error != nil {
  456. return
  457. }
  458. // TODO support save slice data, sql with case?
  459. association.Error = associationDB.Updates(reflectValue.Index(i).Addr().Interface()).Error
  460. }
  461. case reflect.Struct:
  462. // clear old data
  463. if clear && len(values) == 0 {
  464. association.Error = association.Relationship.Field.Set(association.DB.Statement.Context, reflectValue, reflect.New(association.Relationship.Field.IndirectFieldType).Interface())
  465. if association.Relationship.JoinTable == nil && association.Error == nil {
  466. for _, ref := range association.Relationship.References {
  467. if !ref.OwnPrimaryKey && ref.PrimaryValue == "" {
  468. association.Error = ref.ForeignKey.Set(association.DB.Statement.Context, reflectValue, reflect.Zero(ref.ForeignKey.FieldType).Interface())
  469. }
  470. }
  471. }
  472. }
  473. for idx, value := range values {
  474. rv := reflect.Indirect(reflect.ValueOf(value))
  475. appendToRelations(reflectValue, rv, clear && idx == 0)
  476. if association.Error != nil {
  477. return
  478. }
  479. }
  480. if len(values) > 0 {
  481. association.Error = associationDB.Updates(reflectValue.Addr().Interface()).Error
  482. }
  483. }
  484. for _, assignBack := range assignBacks {
  485. fieldValue := reflect.Indirect(association.Relationship.Field.ReflectValueOf(association.DB.Statement.Context, assignBack.Source))
  486. if assignBack.Index > 0 {
  487. reflect.Indirect(assignBack.Dest).Set(fieldValue.Index(assignBack.Index - 1))
  488. } else {
  489. reflect.Indirect(assignBack.Dest).Set(fieldValue)
  490. }
  491. }
  492. }
  493. func (association *Association) buildCondition() *DB {
  494. var (
  495. queryConds = association.Relationship.ToQueryConditions(association.DB.Statement.Context, association.DB.Statement.ReflectValue)
  496. modelValue = reflect.New(association.Relationship.FieldSchema.ModelType).Interface()
  497. tx = association.DB.Model(modelValue)
  498. )
  499. if association.Relationship.JoinTable != nil {
  500. if !tx.Statement.Unscoped && len(association.Relationship.JoinTable.QueryClauses) > 0 {
  501. joinStmt := Statement{DB: tx, Context: tx.Statement.Context, Schema: association.Relationship.JoinTable, Table: association.Relationship.JoinTable.Table, Clauses: map[string]clause.Clause{}}
  502. for _, queryClause := range association.Relationship.JoinTable.QueryClauses {
  503. joinStmt.AddClause(queryClause)
  504. }
  505. joinStmt.Build("WHERE")
  506. if len(joinStmt.SQL.String()) > 0 {
  507. tx.Clauses(clause.Expr{SQL: strings.Replace(joinStmt.SQL.String(), "WHERE ", "", 1), Vars: joinStmt.Vars})
  508. }
  509. }
  510. tx = tx.Session(&Session{QueryFields: true}).Clauses(clause.From{Joins: []clause.Join{{
  511. Table: clause.Table{Name: association.Relationship.JoinTable.Table},
  512. ON: clause.Where{Exprs: queryConds},
  513. }}})
  514. } else {
  515. tx.Clauses(clause.Where{Exprs: queryConds})
  516. }
  517. return tx
  518. }