github.com/systematiccaos/gorm@v1.22.6/schema/relationship.go (about)

     1  package schema
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"strings"
     7  
     8  	"github.com/jinzhu/inflection"
     9  	"github.com/systematiccaos/gorm/clause"
    10  )
    11  
    12  // RelationshipType relationship type
    13  type RelationshipType string
    14  
    15  const (
    16  	HasOne    RelationshipType = "has_one"      // HasOneRel has one relationship
    17  	HasMany   RelationshipType = "has_many"     // HasManyRel has many relationship
    18  	BelongsTo RelationshipType = "belongs_to"   // BelongsToRel belongs to relationship
    19  	Many2Many RelationshipType = "many_to_many" // Many2ManyRel many to many relationship
    20  	has       RelationshipType = "has"
    21  )
    22  
    23  type Relationships struct {
    24  	HasOne    []*Relationship
    25  	BelongsTo []*Relationship
    26  	HasMany   []*Relationship
    27  	Many2Many []*Relationship
    28  	Relations map[string]*Relationship
    29  }
    30  
    31  type Relationship struct {
    32  	Name                     string
    33  	Type                     RelationshipType
    34  	Field                    *Field
    35  	Polymorphic              *Polymorphic
    36  	References               []*Reference
    37  	Schema                   *Schema
    38  	FieldSchema              *Schema
    39  	JoinTable                *Schema
    40  	foreignKeys, primaryKeys []string
    41  }
    42  
    43  type Polymorphic struct {
    44  	PolymorphicID   *Field
    45  	PolymorphicType *Field
    46  	Value           string
    47  }
    48  
    49  type Reference struct {
    50  	PrimaryKey    *Field
    51  	PrimaryValue  string
    52  	ForeignKey    *Field
    53  	OwnPrimaryKey bool
    54  }
    55  
    56  func (schema *Schema) parseRelation(field *Field) *Relationship {
    57  	var (
    58  		err        error
    59  		fieldValue = reflect.New(field.IndirectFieldType).Interface()
    60  		relation   = &Relationship{
    61  			Name:        field.Name,
    62  			Field:       field,
    63  			Schema:      schema,
    64  			foreignKeys: toColumns(field.TagSettings["FOREIGNKEY"]),
    65  			primaryKeys: toColumns(field.TagSettings["REFERENCES"]),
    66  		}
    67  	)
    68  
    69  	cacheStore := schema.cacheStore
    70  
    71  	if relation.FieldSchema, err = getOrParse(fieldValue, cacheStore, schema.namer); err != nil {
    72  		schema.err = err
    73  		return nil
    74  	}
    75  
    76  	if polymorphic := field.TagSettings["POLYMORPHIC"]; polymorphic != "" {
    77  		schema.buildPolymorphicRelation(relation, field, polymorphic)
    78  	} else if many2many := field.TagSettings["MANY2MANY"]; many2many != "" {
    79  		schema.buildMany2ManyRelation(relation, field, many2many)
    80  	} else if belongsTo := field.TagSettings["BELONGSTO"]; belongsTo != "" {
    81  		schema.guessRelation(relation, field, guessBelongs)
    82  	} else {
    83  		switch field.IndirectFieldType.Kind() {
    84  		case reflect.Struct:
    85  			schema.guessRelation(relation, field, guessGuess)
    86  		case reflect.Slice:
    87  			schema.guessRelation(relation, field, guessHas)
    88  		default:
    89  			schema.err = fmt.Errorf("unsupported data type %v for %v on field %s", relation.FieldSchema, schema, field.Name)
    90  		}
    91  	}
    92  
    93  	if relation.Type == has {
    94  		// don't add relations to embedded schema, which might be shared
    95  		if relation.FieldSchema != relation.Schema && relation.Polymorphic == nil && field.OwnerSchema == nil {
    96  			relation.FieldSchema.Relationships.Relations["_"+relation.Schema.Name+"_"+relation.Name] = relation
    97  		}
    98  
    99  		switch field.IndirectFieldType.Kind() {
   100  		case reflect.Struct:
   101  			relation.Type = HasOne
   102  		case reflect.Slice:
   103  			relation.Type = HasMany
   104  		}
   105  	}
   106  
   107  	if schema.err == nil {
   108  		schema.Relationships.Relations[relation.Name] = relation
   109  		switch relation.Type {
   110  		case HasOne:
   111  			schema.Relationships.HasOne = append(schema.Relationships.HasOne, relation)
   112  		case HasMany:
   113  			schema.Relationships.HasMany = append(schema.Relationships.HasMany, relation)
   114  		case BelongsTo:
   115  			schema.Relationships.BelongsTo = append(schema.Relationships.BelongsTo, relation)
   116  		case Many2Many:
   117  			schema.Relationships.Many2Many = append(schema.Relationships.Many2Many, relation)
   118  		}
   119  	}
   120  
   121  	return relation
   122  }
   123  
   124  // User has many Toys, its `Polymorphic` is `Owner`, Pet has one Toy, its `Polymorphic` is `Owner`
   125  //     type User struct {
   126  //       Toys []Toy `gorm:"polymorphic:Owner;"`
   127  //     }
   128  //     type Pet struct {
   129  //       Toy Toy `gorm:"polymorphic:Owner;"`
   130  //     }
   131  //     type Toy struct {
   132  //       OwnerID   int
   133  //       OwnerType string
   134  //     }
   135  func (schema *Schema) buildPolymorphicRelation(relation *Relationship, field *Field, polymorphic string) {
   136  	relation.Polymorphic = &Polymorphic{
   137  		Value:           schema.Table,
   138  		PolymorphicType: relation.FieldSchema.FieldsByName[polymorphic+"Type"],
   139  		PolymorphicID:   relation.FieldSchema.FieldsByName[polymorphic+"ID"],
   140  	}
   141  
   142  	if value, ok := field.TagSettings["POLYMORPHICVALUE"]; ok {
   143  		relation.Polymorphic.Value = strings.TrimSpace(value)
   144  	}
   145  
   146  	if relation.Polymorphic.PolymorphicType == nil {
   147  		schema.err = fmt.Errorf("invalid polymorphic type %v for %v on field %s, missing field %s", relation.FieldSchema, schema, field.Name, polymorphic+"Type")
   148  	}
   149  
   150  	if relation.Polymorphic.PolymorphicID == nil {
   151  		schema.err = fmt.Errorf("invalid polymorphic type %v for %v on field %s, missing field %s", relation.FieldSchema, schema, field.Name, polymorphic+"ID")
   152  	}
   153  
   154  	if schema.err == nil {
   155  		relation.References = append(relation.References, &Reference{
   156  			PrimaryValue: relation.Polymorphic.Value,
   157  			ForeignKey:   relation.Polymorphic.PolymorphicType,
   158  		})
   159  
   160  		primaryKeyField := schema.PrioritizedPrimaryField
   161  		if len(relation.foreignKeys) > 0 {
   162  			if primaryKeyField = schema.LookUpField(relation.foreignKeys[0]); primaryKeyField == nil || len(relation.foreignKeys) > 1 {
   163  				schema.err = fmt.Errorf("invalid polymorphic foreign keys %+v for %v on field %s", relation.foreignKeys, schema, field.Name)
   164  			}
   165  		}
   166  
   167  		// use same data type for foreign keys
   168  		if copyableDataType(primaryKeyField.DataType) {
   169  			relation.Polymorphic.PolymorphicID.DataType = primaryKeyField.DataType
   170  		}
   171  		relation.Polymorphic.PolymorphicID.GORMDataType = primaryKeyField.GORMDataType
   172  		if relation.Polymorphic.PolymorphicID.Size == 0 {
   173  			relation.Polymorphic.PolymorphicID.Size = primaryKeyField.Size
   174  		}
   175  
   176  		relation.References = append(relation.References, &Reference{
   177  			PrimaryKey:    primaryKeyField,
   178  			ForeignKey:    relation.Polymorphic.PolymorphicID,
   179  			OwnPrimaryKey: true,
   180  		})
   181  	}
   182  
   183  	relation.Type = has
   184  }
   185  
   186  func (schema *Schema) buildMany2ManyRelation(relation *Relationship, field *Field, many2many string) {
   187  	relation.Type = Many2Many
   188  
   189  	var (
   190  		err             error
   191  		joinTableFields []reflect.StructField
   192  		fieldsMap       = map[string]*Field{}
   193  		ownFieldsMap    = map[string]bool{} // fix self join many2many
   194  		joinForeignKeys = toColumns(field.TagSettings["JOINFOREIGNKEY"])
   195  		joinReferences  = toColumns(field.TagSettings["JOINREFERENCES"])
   196  	)
   197  
   198  	ownForeignFields := schema.PrimaryFields
   199  	refForeignFields := relation.FieldSchema.PrimaryFields
   200  
   201  	if len(relation.foreignKeys) > 0 {
   202  		ownForeignFields = []*Field{}
   203  		for _, foreignKey := range relation.foreignKeys {
   204  			if field := schema.LookUpField(foreignKey); field != nil {
   205  				ownForeignFields = append(ownForeignFields, field)
   206  			} else {
   207  				schema.err = fmt.Errorf("invalid foreign key: %s", foreignKey)
   208  				return
   209  			}
   210  		}
   211  	}
   212  
   213  	if len(relation.primaryKeys) > 0 {
   214  		refForeignFields = []*Field{}
   215  		for _, foreignKey := range relation.primaryKeys {
   216  			if field := relation.FieldSchema.LookUpField(foreignKey); field != nil {
   217  				refForeignFields = append(refForeignFields, field)
   218  			} else {
   219  				schema.err = fmt.Errorf("invalid foreign key: %s", foreignKey)
   220  				return
   221  			}
   222  		}
   223  	}
   224  
   225  	for idx, ownField := range ownForeignFields {
   226  		joinFieldName := strings.Title(schema.Name) + ownField.Name
   227  		if len(joinForeignKeys) > idx {
   228  			joinFieldName = strings.Title(joinForeignKeys[idx])
   229  		}
   230  
   231  		ownFieldsMap[joinFieldName] = true
   232  		fieldsMap[joinFieldName] = ownField
   233  		joinTableFields = append(joinTableFields, reflect.StructField{
   234  			Name:    joinFieldName,
   235  			PkgPath: ownField.StructField.PkgPath,
   236  			Type:    ownField.StructField.Type,
   237  			Tag:     removeSettingFromTag(ownField.StructField.Tag, "column", "autoincrement", "index", "unique", "uniqueindex"),
   238  		})
   239  	}
   240  
   241  	for idx, relField := range refForeignFields {
   242  		joinFieldName := strings.Title(relation.FieldSchema.Name) + relField.Name
   243  		if len(joinReferences) > idx {
   244  			joinFieldName = strings.Title(joinReferences[idx])
   245  		}
   246  
   247  		if _, ok := ownFieldsMap[joinFieldName]; ok {
   248  			if field.Name != relation.FieldSchema.Name {
   249  				joinFieldName = inflection.Singular(field.Name) + relField.Name
   250  			} else {
   251  				joinFieldName += "Reference"
   252  			}
   253  		}
   254  
   255  		fieldsMap[joinFieldName] = relField
   256  		joinTableFields = append(joinTableFields, reflect.StructField{
   257  			Name:    joinFieldName,
   258  			PkgPath: relField.StructField.PkgPath,
   259  			Type:    relField.StructField.Type,
   260  			Tag:     removeSettingFromTag(relField.StructField.Tag, "column", "autoincrement", "index", "unique", "uniqueindex"),
   261  		})
   262  	}
   263  
   264  	joinTableFields = append(joinTableFields, reflect.StructField{
   265  		Name: strings.Title(schema.Name) + field.Name,
   266  		Type: schema.ModelType,
   267  		Tag:  `gorm:"-"`,
   268  	})
   269  
   270  	if relation.JoinTable, err = Parse(reflect.New(reflect.StructOf(joinTableFields)).Interface(), schema.cacheStore, schema.namer); err != nil {
   271  		schema.err = err
   272  	}
   273  	relation.JoinTable.Name = many2many
   274  	relation.JoinTable.Table = schema.namer.JoinTableName(many2many)
   275  	relation.JoinTable.PrimaryFields = make([]*Field, 0, len(relation.JoinTable.Fields))
   276  
   277  	relName := relation.Schema.Name
   278  	relRefName := relation.FieldSchema.Name
   279  	if relName == relRefName {
   280  		relRefName = relation.Field.Name
   281  	}
   282  
   283  	if _, ok := relation.JoinTable.Relationships.Relations[relName]; !ok {
   284  		relation.JoinTable.Relationships.Relations[relName] = &Relationship{
   285  			Name:        relName,
   286  			Type:        BelongsTo,
   287  			Schema:      relation.JoinTable,
   288  			FieldSchema: relation.Schema,
   289  		}
   290  	} else {
   291  		relation.JoinTable.Relationships.Relations[relName].References = []*Reference{}
   292  	}
   293  
   294  	if _, ok := relation.JoinTable.Relationships.Relations[relRefName]; !ok {
   295  		relation.JoinTable.Relationships.Relations[relRefName] = &Relationship{
   296  			Name:        relRefName,
   297  			Type:        BelongsTo,
   298  			Schema:      relation.JoinTable,
   299  			FieldSchema: relation.FieldSchema,
   300  		}
   301  	} else {
   302  		relation.JoinTable.Relationships.Relations[relRefName].References = []*Reference{}
   303  	}
   304  
   305  	// build references
   306  	for _, f := range relation.JoinTable.Fields {
   307  		if f.Creatable || f.Readable || f.Updatable {
   308  			// use same data type for foreign keys
   309  			if copyableDataType(fieldsMap[f.Name].DataType) {
   310  				f.DataType = fieldsMap[f.Name].DataType
   311  			}
   312  			f.GORMDataType = fieldsMap[f.Name].GORMDataType
   313  			if f.Size == 0 {
   314  				f.Size = fieldsMap[f.Name].Size
   315  			}
   316  			relation.JoinTable.PrimaryFields = append(relation.JoinTable.PrimaryFields, f)
   317  			ownPrimaryField := schema == fieldsMap[f.Name].Schema && ownFieldsMap[f.Name]
   318  
   319  			if ownPrimaryField {
   320  				joinRel := relation.JoinTable.Relationships.Relations[relName]
   321  				joinRel.Field = relation.Field
   322  				joinRel.References = append(joinRel.References, &Reference{
   323  					PrimaryKey: fieldsMap[f.Name],
   324  					ForeignKey: f,
   325  				})
   326  			} else {
   327  				joinRefRel := relation.JoinTable.Relationships.Relations[relRefName]
   328  				if joinRefRel.Field == nil {
   329  					joinRefRel.Field = relation.Field
   330  				}
   331  				joinRefRel.References = append(joinRefRel.References, &Reference{
   332  					PrimaryKey: fieldsMap[f.Name],
   333  					ForeignKey: f,
   334  				})
   335  			}
   336  
   337  			relation.References = append(relation.References, &Reference{
   338  				PrimaryKey:    fieldsMap[f.Name],
   339  				ForeignKey:    f,
   340  				OwnPrimaryKey: ownPrimaryField,
   341  			})
   342  		}
   343  	}
   344  }
   345  
   346  type guessLevel int
   347  
   348  const (
   349  	guessGuess guessLevel = iota
   350  	guessBelongs
   351  	guessEmbeddedBelongs
   352  	guessHas
   353  	guessEmbeddedHas
   354  )
   355  
   356  func (schema *Schema) guessRelation(relation *Relationship, field *Field, cgl guessLevel) {
   357  	var (
   358  		primaryFields, foreignFields []*Field
   359  		primarySchema, foreignSchema = schema, relation.FieldSchema
   360  		gl                           = cgl
   361  	)
   362  
   363  	if gl == guessGuess {
   364  		if field.Schema == relation.FieldSchema {
   365  			gl = guessBelongs
   366  		} else {
   367  			gl = guessHas
   368  		}
   369  	}
   370  
   371  	reguessOrErr := func() {
   372  		switch cgl {
   373  		case guessGuess:
   374  			schema.guessRelation(relation, field, guessBelongs)
   375  		case guessBelongs:
   376  			schema.guessRelation(relation, field, guessEmbeddedBelongs)
   377  		case guessEmbeddedBelongs:
   378  			schema.guessRelation(relation, field, guessHas)
   379  		case guessHas:
   380  			schema.guessRelation(relation, field, guessEmbeddedHas)
   381  		// case guessEmbeddedHas:
   382  		default:
   383  			schema.err = fmt.Errorf("invalid field found for struct %v's field %s: define a valid foreign key for relations or implement the Valuer/Scanner interface", schema, field.Name)
   384  		}
   385  	}
   386  
   387  	switch gl {
   388  	case guessBelongs:
   389  		primarySchema, foreignSchema = relation.FieldSchema, schema
   390  	case guessEmbeddedBelongs:
   391  		if field.OwnerSchema != nil {
   392  			primarySchema, foreignSchema = relation.FieldSchema, field.OwnerSchema
   393  		} else {
   394  			reguessOrErr()
   395  			return
   396  		}
   397  	case guessHas:
   398  	case guessEmbeddedHas:
   399  		if field.OwnerSchema != nil {
   400  			primarySchema, foreignSchema = field.OwnerSchema, relation.FieldSchema
   401  		} else {
   402  			reguessOrErr()
   403  			return
   404  		}
   405  	}
   406  
   407  	if len(relation.foreignKeys) > 0 {
   408  		for _, foreignKey := range relation.foreignKeys {
   409  			if f := foreignSchema.LookUpField(foreignKey); f != nil {
   410  				foreignFields = append(foreignFields, f)
   411  			} else {
   412  				reguessOrErr()
   413  				return
   414  			}
   415  		}
   416  	} else {
   417  		var primaryFields []*Field
   418  
   419  		if len(relation.primaryKeys) > 0 {
   420  			for _, primaryKey := range relation.primaryKeys {
   421  				if f := primarySchema.LookUpField(primaryKey); f != nil {
   422  					primaryFields = append(primaryFields, f)
   423  				}
   424  			}
   425  		} else {
   426  			primaryFields = primarySchema.PrimaryFields
   427  		}
   428  
   429  		for _, primaryField := range primaryFields {
   430  			lookUpName := primarySchema.Name + primaryField.Name
   431  			if gl == guessBelongs {
   432  				lookUpName = field.Name + primaryField.Name
   433  			}
   434  
   435  			lookUpNames := []string{lookUpName}
   436  			if len(primaryFields) == 1 {
   437  				lookUpNames = append(lookUpNames, strings.TrimSuffix(lookUpName, primaryField.Name)+"ID", strings.TrimSuffix(lookUpName, primaryField.Name)+"Id", schema.namer.ColumnName(foreignSchema.Table, strings.TrimSuffix(lookUpName, primaryField.Name)+"ID"))
   438  			}
   439  
   440  			for _, name := range lookUpNames {
   441  				if f := foreignSchema.LookUpField(name); f != nil {
   442  					foreignFields = append(foreignFields, f)
   443  					primaryFields = append(primaryFields, primaryField)
   444  					break
   445  				}
   446  			}
   447  		}
   448  	}
   449  
   450  	if len(foreignFields) == 0 {
   451  		reguessOrErr()
   452  		return
   453  	} else if len(relation.primaryKeys) > 0 {
   454  		for idx, primaryKey := range relation.primaryKeys {
   455  			if f := primarySchema.LookUpField(primaryKey); f != nil {
   456  				if len(primaryFields) < idx+1 {
   457  					primaryFields = append(primaryFields, f)
   458  				} else if f != primaryFields[idx] {
   459  					reguessOrErr()
   460  					return
   461  				}
   462  			} else {
   463  				reguessOrErr()
   464  				return
   465  			}
   466  		}
   467  	} else if len(primaryFields) == 0 {
   468  		if len(foreignFields) == 1 && primarySchema.PrioritizedPrimaryField != nil {
   469  			primaryFields = append(primaryFields, primarySchema.PrioritizedPrimaryField)
   470  		} else if len(primarySchema.PrimaryFields) == len(foreignFields) {
   471  			primaryFields = append(primaryFields, primarySchema.PrimaryFields...)
   472  		} else {
   473  			reguessOrErr()
   474  			return
   475  		}
   476  	}
   477  
   478  	// build references
   479  	for idx, foreignField := range foreignFields {
   480  		// use same data type for foreign keys
   481  		if copyableDataType(primaryFields[idx].DataType) {
   482  			foreignField.DataType = primaryFields[idx].DataType
   483  		}
   484  		foreignField.GORMDataType = primaryFields[idx].GORMDataType
   485  		if foreignField.Size == 0 {
   486  			foreignField.Size = primaryFields[idx].Size
   487  		}
   488  
   489  		relation.References = append(relation.References, &Reference{
   490  			PrimaryKey:    primaryFields[idx],
   491  			ForeignKey:    foreignField,
   492  			OwnPrimaryKey: (schema == primarySchema && gl == guessHas) || (field.OwnerSchema == primarySchema && gl == guessEmbeddedHas),
   493  		})
   494  	}
   495  
   496  	if gl == guessHas || gl == guessEmbeddedHas {
   497  		relation.Type = has
   498  	} else {
   499  		relation.Type = BelongsTo
   500  	}
   501  }
   502  
   503  type Constraint struct {
   504  	Name            string
   505  	Field           *Field
   506  	Schema          *Schema
   507  	ForeignKeys     []*Field
   508  	ReferenceSchema *Schema
   509  	References      []*Field
   510  	OnDelete        string
   511  	OnUpdate        string
   512  }
   513  
   514  func (rel *Relationship) ParseConstraint() *Constraint {
   515  	str := rel.Field.TagSettings["CONSTRAINT"]
   516  	if str == "-" {
   517  		return nil
   518  	}
   519  
   520  	if rel.Type == BelongsTo {
   521  		for _, r := range rel.FieldSchema.Relationships.Relations {
   522  			if r != rel && r.FieldSchema == rel.Schema && len(rel.References) == len(r.References) {
   523  				matched := true
   524  				for idx, ref := range r.References {
   525  					if !(rel.References[idx].PrimaryKey == ref.PrimaryKey && rel.References[idx].ForeignKey == ref.ForeignKey &&
   526  						rel.References[idx].PrimaryValue == ref.PrimaryValue) {
   527  						matched = false
   528  					}
   529  				}
   530  
   531  				if matched {
   532  					return nil
   533  				}
   534  			}
   535  		}
   536  	}
   537  
   538  	var (
   539  		name     string
   540  		idx      = strings.Index(str, ",")
   541  		settings = ParseTagSetting(str, ",")
   542  	)
   543  
   544  	// optimize match english letters and midline
   545  	// The following code is basically called in for.
   546  	// In order to avoid the performance problems caused by repeated compilation of regular expressions,
   547  	// it only needs to be done once outside, so optimization is done here.
   548  	if idx != -1 && regEnLetterAndMidline.MatchString(str[0:idx]) {
   549  		name = str[0:idx]
   550  	} else {
   551  		name = rel.Schema.namer.RelationshipFKName(*rel)
   552  	}
   553  
   554  	constraint := Constraint{
   555  		Name:     name,
   556  		Field:    rel.Field,
   557  		OnUpdate: settings["ONUPDATE"],
   558  		OnDelete: settings["ONDELETE"],
   559  	}
   560  
   561  	for _, ref := range rel.References {
   562  		if ref.PrimaryKey != nil && (rel.JoinTable == nil || ref.OwnPrimaryKey) {
   563  			constraint.ForeignKeys = append(constraint.ForeignKeys, ref.ForeignKey)
   564  			constraint.References = append(constraint.References, ref.PrimaryKey)
   565  
   566  			if ref.OwnPrimaryKey {
   567  				constraint.Schema = ref.ForeignKey.Schema
   568  				constraint.ReferenceSchema = rel.Schema
   569  			} else {
   570  				constraint.Schema = rel.Schema
   571  				constraint.ReferenceSchema = ref.PrimaryKey.Schema
   572  			}
   573  		}
   574  	}
   575  
   576  	return &constraint
   577  }
   578  
   579  func (rel *Relationship) ToQueryConditions(reflectValue reflect.Value) (conds []clause.Expression) {
   580  	table := rel.FieldSchema.Table
   581  	foreignFields := []*Field{}
   582  	relForeignKeys := []string{}
   583  
   584  	if rel.JoinTable != nil {
   585  		table = rel.JoinTable.Table
   586  		for _, ref := range rel.References {
   587  			if ref.OwnPrimaryKey {
   588  				foreignFields = append(foreignFields, ref.PrimaryKey)
   589  				relForeignKeys = append(relForeignKeys, ref.ForeignKey.DBName)
   590  			} else if ref.PrimaryValue != "" {
   591  				conds = append(conds, clause.Eq{
   592  					Column: clause.Column{Table: rel.JoinTable.Table, Name: ref.ForeignKey.DBName},
   593  					Value:  ref.PrimaryValue,
   594  				})
   595  			} else {
   596  				conds = append(conds, clause.Eq{
   597  					Column: clause.Column{Table: rel.JoinTable.Table, Name: ref.ForeignKey.DBName},
   598  					Value:  clause.Column{Table: rel.FieldSchema.Table, Name: ref.PrimaryKey.DBName},
   599  				})
   600  			}
   601  		}
   602  	} else {
   603  		for _, ref := range rel.References {
   604  			if ref.OwnPrimaryKey {
   605  				relForeignKeys = append(relForeignKeys, ref.ForeignKey.DBName)
   606  				foreignFields = append(foreignFields, ref.PrimaryKey)
   607  			} else if ref.PrimaryValue != "" {
   608  				conds = append(conds, clause.Eq{
   609  					Column: clause.Column{Table: rel.FieldSchema.Table, Name: ref.ForeignKey.DBName},
   610  					Value:  ref.PrimaryValue,
   611  				})
   612  			} else {
   613  				relForeignKeys = append(relForeignKeys, ref.PrimaryKey.DBName)
   614  				foreignFields = append(foreignFields, ref.ForeignKey)
   615  			}
   616  		}
   617  	}
   618  
   619  	_, foreignValues := GetIdentityFieldValuesMap(reflectValue, foreignFields)
   620  	column, values := ToQueryValues(table, relForeignKeys, foreignValues)
   621  
   622  	conds = append(conds, clause.IN{Column: column, Values: values})
   623  	return
   624  }
   625  
   626  func copyableDataType(str DataType) bool {
   627  	for _, s := range []string{"auto_increment", "primary key"} {
   628  		if strings.Contains(strings.ToLower(string(str)), s) {
   629  			return false
   630  		}
   631  	}
   632  	return true
   633  }