Repository: go-gorm/gorm
Pull request #5089 (2022-02-19 09:00:22)

Add Serializer, Update migrator ColumnType interface
<!--
Make sure these boxes checked before submitting your pull request.

For significant changes, please open an issue to make an agreement on an implementation design/plan first before starting it.
-->

- [] Do only one thing
- [] Non breaking API changes
- [] Tested

### What did this pull request do?

<!--
provide a general description of the code changes in your pull request
-->

### User Case Description

<!-- Your use case -->



Patch:
diff --git a/association.go b/association.go
index 62c25b7..09e79ca 100644
--- a/association.go
+++ b/association.go
@@ -79,10 +79,10 @@ func (association *Association) Replace(values ...interface{}) error {
 				switch reflectValue.Kind() {
 				case reflect.Slice, reflect.Array:
 					for i := 0; i < reflectValue.Len(); i++ {
-						association.Error = rel.Field.Set(reflectValue.Index(i), reflect.Zero(rel.Field.FieldType).Interface())
+						association.Error = rel.Field.Set(association.DB.Statement.Context, reflectValue.Index(i), reflect.Zero(rel.Field.FieldType).Interface())
 					}
 				case reflect.Struct:
-					association.Error = rel.Field.Set(reflectValue, reflect.Zero(rel.Field.FieldType).Interface())
+					association.Error = rel.Field.Set(association.DB.Statement.Context, reflectValue, reflect.Zero(rel.Field.FieldType).Interface())
 				}
 
 				for _, ref := range rel.References {
@@ -96,12 +96,12 @@ func (association *Association) Replace(values ...interface{}) error {
 				primaryFields []*schema.Field
 				foreignKeys   []string
 				updateMap     = map[string]interface{}{}
-				relValues     = schema.GetRelationsValues(reflectValue, []*schema.Relationship{rel})
+				relValues     = schema.GetRelationsValues(association.DB.Statement.Context, reflectValue, []*schema.Relationship{rel})
 				modelValue    = reflect.New(rel.FieldSchema.ModelType).Interface()
 				tx            = association.DB.Model(modelValue)
 			)
 
-			if _, rvs := schema.GetIdentityFieldValuesMap(relValues, rel.FieldSchema.PrimaryFields); len(rvs) > 0 {
+			if _, rvs := schema.GetIdentityFieldValuesMap(association.DB.Statement.Context, relValues, rel.FieldSchema.PrimaryFields); len(rvs) > 0 {
 				if column, values := schema.ToQueryValues(rel.FieldSchema.Table, rel.FieldSchema.PrimaryFieldDBNames, rvs); len(values) > 0 {
 					tx.Not(clause.IN{Column: column, Values: values})
 				}
@@ -117,7 +117,7 @@ func (association *Association) Replace(values ...interface{}) error {
 				}
 			}
 
-			if _, pvs := schema.GetIdentityFieldValuesMap(reflectValue, primaryFields); len(pvs) > 0 {
+			if _, pvs := schema.GetIdentityFieldValuesMap(association.DB.Statement.Context, reflectValue, primaryFields); len(pvs) > 0 {
 				column, values := schema.ToQueryValues(rel.FieldSchema.Table, foreignKeys, pvs)
 				association.Error = tx.Where(clause.IN{Column: column, Values: values}).UpdateColumns(updateMap).Error
 			}
@@ -143,14 +143,14 @@ func (association *Association) Replace(values ...interface{}) error {
 				}
 			}
 
-			_, pvs := schema.GetIdentityFieldValuesMap(reflectValue, primaryFields)
+			_, pvs := schema.GetIdentityFieldValuesMap(association.DB.Statement.Context, reflectValue, primaryFields)
 			if column, values := schema.ToQueryValues(rel.JoinTable.Table, joinPrimaryKeys, pvs); len(values) > 0 {
 				tx.Where(clause.IN{Column: column, Values: values})
 			} else {
 				return ErrPrimaryKeyRequired
 			}
 
-			_, rvs := schema.GetIdentityFieldValuesMapFromValues(values, relPrimaryFields)
+			_, rvs := schema.GetIdentityFieldValuesMapFromValues(association.DB.Statement.Context, values, relPrimaryFields)
 			if relColumn, relValues := schema.ToQueryValues(rel.JoinTable.Table, joinRelPrimaryKeys, rvs); len(relValues) > 0 {
 				tx.Where(clause.Not(clause.IN{Column: relColumn, Values: relValues}))
 			}
@@ -186,11 +186,11 @@ func (association *Association) Delete(values ...interface{}) error {
 		case schema.BelongsTo:
 			tx := association.DB.Model(reflect.New(rel.Schema.ModelType).Interface())
 
-			_, pvs := schema.GetIdentityFieldValuesMap(reflectValue, rel.Schema.PrimaryFields)
+			_, pvs := schema.GetIdentityFieldValuesMap(association.DB.Statement.Context, reflectValue, rel.Schema.PrimaryFields)
 			pcolumn, pvalues := schema.ToQueryValues(rel.Schema.Table, rel.Schema.PrimaryFieldDBNames, pvs)
 			conds = append(conds, clause.IN{Column: pcolumn, Values: pvalues})
 
-			_, rvs := schema.GetIdentityFieldValuesMapFromValues(values, primaryFields)
+			_, rvs := schema.GetIdentityFieldValuesMapFromValues(association.DB.Statement.Context, values, primaryFields)
 			relColumn, relValues := schema.ToQueryValues(rel.Schema.Table, foreignKeys, rvs)
 			conds = append(conds, clause.IN{Column: relColumn, Values: relValues})
 
@@ -198,11 +198,11 @@ func (association *Association) Delete(values ...interface{}) error {
 		case schema.HasOne, schema.HasMany:
 			tx := association.DB.Model(reflect.New(rel.FieldSchema.ModelType).Interface())
 
-			_, pvs := schema.GetIdentityFieldValuesMap(reflectValue, primaryFields)
+			_, pvs := schema.GetIdentityFieldValuesMap(association.DB.Statement.Context, reflectValue, primaryFields)
 			pcolumn, pvalues := schema.ToQueryValues(rel.FieldSchema.Table, foreignKeys, pvs)
 			conds = append(conds, clause.IN{Column: pcolumn, Values: pvalues})
 
-			_, rvs := schema.GetIdentityFieldValuesMapFromValues(values, rel.FieldSchema.PrimaryFields)
+			_, rvs := schema.GetIdentityFieldValuesMapFromValues(association.DB.Statement.Context, values, rel.FieldSchema.PrimaryFields)
 			relColumn, relValues := schema.ToQueryValues(rel.FieldSchema.Table, rel.FieldSchema.PrimaryFieldDBNames, rvs)
 			conds = append(conds, clause.IN{Column: relColumn, Values: relValues})
 
@@ -228,11 +228,11 @@ func (association *Association) Delete(values ...interface{}) error {
 				}
 			}
 
-			_, pvs := schema.GetIdentityFieldValuesMap(reflectValue, primaryFields)
+			_, pvs := schema.GetIdentityFieldValuesMap(association.DB.Statement.Context, reflectValue, primaryFields)
 			pcolumn, pvalues := schema.ToQueryValues(rel.JoinTable.Table, joinPrimaryKeys, pvs)
 			conds = append(conds, clause.IN{Column: pcolumn, Values: pvalues})
 
-			_, rvs := schema.GetIdentityFieldValuesMapFromValues(values, relPrimaryFields)
+			_, rvs := schema.GetIdentityFieldValuesMapFromValues(association.DB.Statement.Context, values, relPrimaryFields)
 			relColumn, relValues := schema.ToQueryValues(rel.JoinTable.Table, joinRelPrimaryKeys, rvs)
 			conds = append(conds, clause.IN{Column: relColumn, Values: relValues})
 
@@ -241,11 +241,11 @@ func (association *Association) Delete(values ...interface{}) error {
 
 		if association.Error == nil {
 			// clean up deleted values's foreign key
-			relValuesMap, _ := schema.GetIdentityFieldValuesMapFromValues(values, rel.FieldSchema.PrimaryFields)
+			relValuesMap, _ := schema.GetIdentityFieldValuesMapFromValues(association.DB.Statement.Context, values, rel.FieldSchema.PrimaryFields)
 
 			cleanUpDeletedRelations := func(data reflect.Value) {
-				if _, zero := rel.Field.ValueOf(data); !zero {
-					fieldValue := reflect.Indirect(rel.Field.ReflectValueOf(data))
+				if _, zero := rel.Field.ValueOf(association.DB.Statement.Context, data); !zero {
+					fieldValue := reflect.Indirect(rel.Field.ReflectValueOf(association.DB.Statement.Context, data))
 					primaryValues := make([]interface{}, len(rel.FieldSchema.PrimaryFields))
 
 					switch fieldValue.Kind() {
@@ -253,7 +253,7 @@ func (association *Association) Delete(values ...interface{}) error {
 						validFieldValues := reflect.Zero(rel.Field.IndirectFieldType)
 						for i := 0; i < fieldValue.Len(); i++ {
 							for idx, field := range rel.FieldSchema.PrimaryFields {
-								primaryValues[idx], _ = field.ValueOf(fieldValue.Index(i))
+								primaryValues[idx], _ = field.ValueOf(association.DB.Statement.Context, fieldValue.Index(i))
 							}
 
 							if _, ok := relValuesMap[utils.ToStringKey(primaryValues...)]; !ok {
@@ -261,23 +261,23 @@ func (association *Association) Delete(values ...interface{}) error {
 							}
 						}
 
-						association.Error = rel.Field.Set(data, validFieldValues.Interface())
+						association.Error = rel.Field.Set(association.DB.Statement.Context, data, validFieldValues.Interface())
 					case reflect.Struct:
 						for idx, field := range rel.FieldSchema.PrimaryFields {
-							primaryValues[idx], _ = field.ValueOf(fieldValue)
+							primaryValues[idx], _ = field.ValueOf(association.DB.Statement.Context, fieldValue)
 						}
 
 						if _, ok := relValuesMap[utils.ToStringKey(primaryValues...)]; ok {
-							if association.Error = rel.Field.Set(data, reflect.Zero(rel.FieldSchema.ModelType).Interface()); association.Error != nil {
+							if association.Error = rel.Field.Set(association.DB.Statement.Context, data, reflect.Zero(rel.FieldSchema.ModelType).Interface()); association.Error != nil {
 								break
 							}
 
 							if rel.JoinTable == nil {
 								for _, ref := range rel.References {
 									if ref.OwnPrimaryKey || ref.PrimaryValue != "" {
-										association.Error = ref.ForeignKey.Set(fieldValue, reflect.Zero(ref.ForeignKey.FieldType).Interface())
+										association.Error = ref.ForeignKey.Set(association.DB.Statement.Context, fieldValue, reflect.Zero(ref.ForeignKey.FieldType).Interface())
 									} else {
-										association.Error = ref.ForeignKey.Set(data, reflect.Zero(ref.ForeignKey.FieldType).Interface())
+										association.Error = ref.ForeignKey.Set(association.DB.Statement.Context, data, reflect.Zero(ref.ForeignKey.FieldType).Interface())
 									}
 								}
 							}
@@ -329,14 +329,14 @@ func (association *Association) saveAssociation(clear bool, values ...interface{
 			switch rv.Kind() {
 			case reflect.Slice, reflect.Array:
 				if rv.Len() > 0 {
-					association.Error = association.Relationship.Field.Set(source, rv.Index(0).Addr().Interface())
+					association.Error = association.Relationship.Field.Set(association.DB.Statement.Context, source, rv.Index(0).Addr().Interface())
 
 					if association.Relationship.Field.FieldType.Kind() == reflect.Struct {
 						assignBacks = append(assignBacks, assignBack{Source: source, Dest: rv.Index(0)})
 					}
 				}
 			case reflect.Struct:
-				association.Error = association.Relationship.Field.Set(source, rv.Addr().Interface())
+				association.Error = association.Relationship.Field.Set(association.DB.Statement.Context, source, rv.Addr().Interface())
 
 				if association.Relationship.Field.FieldType.Kind() == reflect.Struct {
 					assignBacks = append(assignBacks, assignBack{Source: source, Dest: rv})
@@ -344,7 +344,7 @@ func (association *Association) saveAssociation(clear bool, values ...interface{
 			}
 		case schema.HasMany, schema.Many2Many:
 			elemType := association.Relationship.Field.IndirectFieldType.Elem()
-			fieldValue := reflect.Indirect(association.Relationship.Field.ReflectValueOf(source))
+			fieldValue := reflect.Indirect(association.Relationship.Field.ReflectValueOf(association.DB.Statement.Context, source))
 			if clear {
 				fieldValue = reflect.New(association.Relationship.Field.IndirectFieldType).Elem()
 			}
@@ -373,7 +373,7 @@ func (association *Association) saveAssociation(clear bool, values ...interface{
 			}
 
 			if association.Error == nil {
-				association.Error = association.Relationship.Field.Set(source, fieldValue.Interface())
+				association.Error = association.Relationship.Field.Set(association.DB.Statement.Context, source, fieldValue.Interface())
 			}
 		}
 	}
@@ -421,7 +421,7 @@ func (association *Association) saveAssociation(clear bool, values ...interface{
 			// clear old data
 			if clear && len(values) == 0 {
 				for i := 0; i < reflectValue.Len(); i++ {
-					if err := association.Relationship.Field.Set(reflectValue.Index(i), reflect.New(association.Relationship.Field.IndirectFieldType).Interface()); err != nil {
+					if err := association.Relationship.Field.Set(association.DB.Statement.Context, reflectValue.Index(i), reflect.New(association.Relationship.Field.IndirectFieldType).Interface()); err != nil {
 						association.Error = err
 						break
 					}
@@ -429,7 +429,7 @@ func (association *Association) saveAssociation(clear bool, values ...interface{
 					if association.Relationship.JoinTable == nil {
 						for _, ref := range association.Relationship.References {
 							if !ref.OwnPrimaryKey && ref.PrimaryValue == "" {
-								if err := ref.ForeignKey.Set(reflectValue.Index(i), reflect.Zero(ref.ForeignKey.FieldType).Interface()); err != nil {
+								if err := ref.ForeignKey.Set(association.DB.Statement.Context, reflectValue.Index(i), reflect.Zero(ref.ForeignKey.FieldType).Interface()); err != nil {
 									association.Error = err
 									break
 								}
@@ -453,12 +453,12 @@ func (association *Association) saveAssociation(clear bool, values ...interface{
 	case reflect.Struct:
 		// clear old data
 		if clear && len(values) == 0 {
-			association.Error = association.Relationship.Field.Set(reflectValue, reflect.New(association.Relationship.Field.IndirectFieldType).Interface())
+			association.Error = association.Relationship.Field.Set(association.DB.Statement.Context, reflectValue, reflect.New(association.Relationship.Field.IndirectFieldType).Interface())
 
 			if association.Relationship.JoinTable == nil && association.Error == nil {
 				for _, ref := range association.Relationship.References {
 					if !ref.OwnPrimaryKey && ref.PrimaryValue == "" {
-						association.Error = ref.ForeignKey.Set(reflectValue, reflect.Zero(ref.ForeignKey.FieldType).Interface())
+						association.Error = ref.ForeignKey.Set(association.DB.Statement.Context, reflectValue, reflect.Zero(ref.ForeignKey.FieldType).Interface())
 					}
 				}
 			}
@@ -475,7 +475,7 @@ func (association *Association) saveAssociation(clear bool, values ...interface{
 	}
 
 	for _, assignBack := range assignBacks {
-		fieldValue := reflect.Indirect(association.Relationship.Field.ReflectValueOf(assignBack.Source))
+		fieldValue := reflect.Indirect(association.Relationship.Field.ReflectValueOf(association.DB.Statement.Context, assignBack.Source))
 		if assignBack.Index > 0 {
 			reflect.Indirect(assignBack.Dest).Set(fieldValue.Index(assignBack.Index - 1))
 		} else {
@@ -486,7 +486,7 @@ func (association *Association) saveAssociation(clear bool, values ...interface{
 
 func (association *Association) buildCondition() *DB {
 	var (
-		queryConds = association.Relationship.ToQueryConditions(association.DB.Statement.ReflectValue)
+		queryConds = association.Relationship.ToQueryConditions(association.DB.Statement.Context, association.DB.Statement.ReflectValue)
 		modelValue = reflect.New(association.Relationship.FieldSchema.ModelType).Interface()
 		tx         = association.DB.Model(modelValue)
 	)
diff --git a/callbacks/associations.go b/callbacks/associations.go
index 75bd6c6..d6fd21d 100644
--- a/callbacks/associations.go
+++ b/callbacks/associations.go
@@ -24,8 +24,8 @@ func SaveBeforeAssociations(create bool) func(db *gorm.DB) {
 				setupReferences := func(obj reflect.Value, elem reflect.Value) {
 					for _, ref := range rel.References {
 						if !ref.OwnPrimaryKey {
-							pv, _ := ref.PrimaryKey.ValueOf(elem)
-							db.AddError(ref.ForeignKey.Set(obj, pv))
+							pv, _ := ref.PrimaryKey.ValueOf(db.Statement.Context, elem)
+							db.AddError(ref.ForeignKey.Set(db.Statement.Context, obj, pv))
 
 							if dest, ok := db.Statement.Dest.(map[string]interface{}); ok {
 								dest[ref.ForeignKey.DBName] = pv
@@ -57,8 +57,8 @@ func SaveBeforeAssociations(create bool) func(db *gorm.DB) {
 							break
 						}
 
-						if _, zero := rel.Field.ValueOf(obj); !zero { // check belongs to relation value
-							rv := rel.Field.ReflectValueOf(obj) // relation reflect value
+						if _, zero := rel.Field.ValueOf(db.Statement.Context, obj); !zero { // check belongs to relation value
+							rv := rel.Field.ReflectValueOf(db.Statement.Context, obj) // relation reflect value
 							objs = append(objs, obj)
 							if isPtr {
 								elems = reflect.Append(elems, rv)
@@ -76,8 +76,8 @@ func SaveBeforeAssociations(create bool) func(db *gorm.DB) {
 						}
 					}
 				case reflect.Struct:
-					if _, zero := rel.Field.ValueOf(db.Statement.ReflectValue); !zero {
-						rv := rel.Field.ReflectValueOf(db.Statement.ReflectValue) // relation reflect value
+					if _, zero := rel.Field.ValueOf(db.Statement.Context, db.Statement.ReflectValue); !zero {
+						rv := rel.Field.ReflectValueOf(db.Statement.Context, db.Statement.ReflectValue) // relation reflect value
 						if rv.Kind() != reflect.Ptr {
 							rv = rv.Addr()
 						}
@@ -120,18 +120,18 @@ func SaveAfterAssociations(create bool) func(db *gorm.DB) {
 						obj := db.Statement.ReflectValue.Index(i)
 
 						if reflect.Indirect(obj).Kind() == reflect.Struct {
-							if _, zero := rel.Field.ValueOf(obj); !zero {
-								rv := rel.Field.ReflectValueOf(obj)
+							if _, zero := rel.Field.ValueOf(db.Statement.Context, obj); !zero {
+								rv := rel.Field.ReflectValueOf(db.Statement.Context, obj)
 								if rv.Kind() != reflect.Ptr {
 									rv = rv.Addr()
 								}
 
 								for _, ref := range rel.References {
 									if ref.OwnPrimaryKey {
-										fv, _ := ref.PrimaryKey.ValueOf(obj)
-										db.AddError(ref.ForeignKey.Set(rv, fv))
+										fv, _ := ref.PrimaryKey.ValueOf(db.Statement.Context, obj)
+										db.AddError(ref.ForeignKey.Set(db.Statement.Context, rv, fv))
 									} else if ref.PrimaryValue != "" {
-										db.AddError(ref.ForeignKey.Set(rv, ref.PrimaryValue))
+										db.AddError(ref.ForeignKey.Set(db.Statement.Context, rv, ref.PrimaryValue))
 									}
 								}
 
@@ -149,8 +149,8 @@ func SaveAfterAssociations(create bool) func(db *gorm.DB) {
 						saveAssociations(db, rel, elems.Interface(), selectColumns, restricted, assignmentColumns)
 					}
 				case reflect.Struct:
-					if _, zero := rel.Field.ValueOf(db.Statement.ReflectValue); !zero {
-						f := rel.Field.ReflectValueOf(db.Statement.ReflectValue)
+					if _, zero := rel.Field.ValueOf(db.Statement.Context, db.Statement.ReflectValue); !zero {
+						f := rel.Field.ReflectValueOf(db.Statement.Context, db.Statement.ReflectValue)
 						if f.Kind() != reflect.Ptr {
 							f = f.Addr()
 						}
@@ -158,10 +158,10 @@ func SaveAfterAssociations(create bool) func(db *gorm.DB) {
 						assignmentColumns := make([]string, 0, len(rel.References))
 						for _, ref := range rel.References {
 							if ref.OwnPrimaryKey {
-								fv, _ := ref.PrimaryKey.ValueOf(db.Statement.ReflectValue)
-								ref.ForeignKey.Set(f, fv)
+								fv, _ := ref.PrimaryKey.ValueOf(db.Statement.Context, db.Statement.ReflectValue)
+								ref.ForeignKey.Set(db.Statement.Context, f, fv)
 							} else if ref.PrimaryValue != "" {
-								ref.ForeignKey.Set(f, ref.PrimaryValue)
+								ref.ForeignKey.Set(db.Statement.Context, f, ref.PrimaryValue)
 							}
 							assignmentColumns = append(assignmentColumns, ref.ForeignKey.DBName)
 						}
@@ -185,23 +185,23 @@ func SaveAfterAssociations(create bool) func(db *gorm.DB) {
 				elems := reflect.MakeSlice(reflect.SliceOf(fieldType), 0, 10)
 				identityMap := map[string]bool{}
 				appendToElems := func(v reflect.Value) {
-					if _, zero := rel.Field.ValueOf(v); !zero {
-						f := reflect.Indirect(rel.Field.ReflectValueOf(v))
+					if _, zero := rel.Field.ValueOf(db.Statement.Context, v); !zero {
+						f := reflect.Indirect(rel.Field.ReflectValueOf(db.Statement.Context, v))
 
 						for i := 0; i < f.Len(); i++ {
 							elem := f.Index(i)
 							for _, ref := range rel.References {
 								if ref.OwnPrimaryKey {
-									pv, _ := ref.PrimaryKey.ValueOf(v)
-									ref.ForeignKey.Set(elem, pv)
+									pv, _ := ref.PrimaryKey.ValueOf(db.Statement.Context, v)
+									ref.ForeignKey.Set(db.Statement.Context, elem, pv)
 								} else if ref.PrimaryValue != "" {
-									ref.ForeignKey.Set(elem, ref.PrimaryValue)
+									ref.ForeignKey.Set(db.Statement.Context, elem, ref.PrimaryValue)
 								}
 							}
 
 							relPrimaryValues := make([]interface{}, 0, len(rel.FieldSchema.PrimaryFields))
 							for _, pf := range rel.FieldSchema.PrimaryFields {
-								if pfv, ok := pf.ValueOf(elem); !ok {
+								if pfv, ok := pf.ValueOf(db.Statement.Context, elem); !ok {
 									relPrimaryValues = append(relPrimaryValues, pfv)
 								}
 							}
@@ -260,21 +260,21 @@ func SaveAfterAssociations(create bool) func(db *gorm.DB) {
 					joinValue := reflect.New(rel.JoinTable.ModelType)
 					for _, ref := range rel.References {
 						if ref.OwnPrimaryKey {
-							fv, _ := ref.PrimaryKey.ValueOf(obj)
-							ref.ForeignKey.Set(joinValue, fv)
+							fv, _ := ref.PrimaryKey.ValueOf(db.Statement.Context, obj)
+							ref.ForeignKey.Set(db.Statement.Context, joinValue, fv)
 						} else if ref.PrimaryValue != "" {
-							ref.ForeignKey.Set(joinValue, ref.PrimaryValue)
+							ref.ForeignKey.Set(db.Statement.Context, joinValue, ref.PrimaryValue)
 						} else {
-							fv, _ := ref.PrimaryKey.ValueOf(elem)
-							ref.ForeignKey.Set(joinValue, fv)
+							fv, _ := ref.PrimaryKey.ValueOf(db.Statement.Context, elem)
+							ref.ForeignKey.Set(db.Statement.Context, joinValue, fv)
 						}
 					}
 					joins = reflect.Append(joins, joinValue)
 				}
 
 				appendToElems := func(v reflect.Value) {
-					if _, zero := rel.Field.ValueOf(v); !zero {
-						f := reflect.Indirect(rel.Field.ReflectValueOf(v))
+					if _, zero := rel.Field.ValueOf(db.Statement.Context, v); !zero {
+						f := reflect.Indirect(rel.Field.ReflectValueOf(db.Statement.Context, v))
 
 						for i := 0; i < f.Len(); i++ {
 							elem := f.Index(i)
diff --git a/callbacks/create.go b/callbacks/create.go
index 2911312..b0964e2 100644
--- a/callbacks/create.go
+++ b/callbacks/create.go
@@ -117,9 +117,9 @@ func Create(config *Config) func(db *gorm.DB) {
 							break
 						}
 
-						_, isZero := db.Statement.Schema.PrioritizedPrimaryField.ValueOf(rv)
+						_, isZero := db.Statement.Schema.PrioritizedPrimaryField.ValueOf(db.Statement.Context, rv)
 						if isZero {
-							db.Statement.Schema.PrioritizedPrimaryField.Set(rv, insertID)
+							db.Statement.Schema.PrioritizedPrimaryField.Set(db.Statement.Context, rv, insertID)
 							insertID -= db.Statement.Schema.PrioritizedPrimaryField.AutoIncrementIncrement
 						}
 					}
@@ -130,16 +130,16 @@ func Create(config *Config) func(db *gorm.DB) {
 							break
 						}
 
-						if _, isZero := db.Statement.Schema.PrioritizedPrimaryField.ValueOf(rv); isZero {
-							db.Statement.Schema.PrioritizedPrimaryField.Set(rv, insertID)
+						if _, isZero := db.Statement.Schema.PrioritizedPrimaryField.ValueOf(db.Statement.Context, rv); isZero {
+							db.Statement.Schema.PrioritizedPrimaryField.Set(db.Statement.Context, rv, insertID)
 							insertID += db.Statement.Schema.PrioritizedPrimaryField.AutoIncrementIncrement
 						}
 					}
 				}
 			case reflect.Struct:
-				_, isZero := db.Statement.Schema.PrioritizedPrimaryField.ValueOf(db.Statement.ReflectValue)
+				_, isZero := db.Statement.Schema.PrioritizedPrimaryField.ValueOf(db.Statement.Context, db.Statement.ReflectValue)
 				if isZero {
-					db.Statement.Schema.PrioritizedPrimaryField.Set(db.Statement.ReflectValue, insertID)
+					db.Statement.Schema.PrioritizedPrimaryField.Set(db.Statement.Context, db.Statement.ReflectValue, insertID)
 				}
 			}
 		}
@@ -219,23 +219,23 @@ func ConvertToCreateValues(stmt *gorm.Statement) (values clause.Values) {
 				values.Values[i] = make([]interface{}, len(values.Columns))
 				for idx, column := range values.Columns {
 					field := stmt.Schema.FieldsByDBName[column.Name]
-					if values.Values[i][idx], isZero = field.ValueOf(rv); isZero {
+					if values.Values[i][idx], isZero = field.ValueOf(stmt.Context, rv); isZero {
 						if field.DefaultValueInterface != nil {
 							values.Values[i][idx] = field.DefaultValueInterface
-							field.Set(rv, field.DefaultValueInterface)
+							field.Set(stmt.Context, rv, field.DefaultValueInterface)
 						} else if field.AutoCreateTime > 0 || field.AutoUpdateTime > 0 {
-							field.Set(rv, curTime)
-							values.Values[i][idx], _ = field.ValueOf(rv)
+							field.Set(stmt.Context, rv, curTime)
+							values.Values[i][idx], _ = field.ValueOf(stmt.Context, rv)
 						}
 					} else if field.AutoUpdateTime > 0 && updateTrackTime {
-						field.Set(rv, curTime)
-						values.Values[i][idx], _ = field.ValueOf(rv)
+						field.Set(stmt.Context, rv, curTime)
+						values.Values[i][idx], _ = field.ValueOf(stmt.Context, rv)
 					}
 				}
 
 				for _, field := range stmt.Schema.FieldsWithDefaultDBValue {
 					if v, ok := selectColumns[field.DBName]; (ok && v) || (!ok && !restricted) {
-						if rvOfvalue, isZero := field.ValueOf(rv); !isZero {
+						if rvOfvalue, isZero := field.ValueOf(stmt.Context, rv); !isZero {
 							if len(defaultValueFieldsHavingValue[field]) == 0 {
 								defaultValueFieldsHavingValue[field] = make([]interface{}, rValLen)
 							}
@@ -259,23 +259,23 @@ func ConvertToCreateValues(stmt *gorm.Statement) (values clause.Values) {
 			values.Values = [][]interface{}{make([]interface{}, len(values.Columns))}
 			for idx, column := range values.Columns {
 				field := stmt.Schema.FieldsByDBName[column.Name]
-				if values.Values[0][idx], isZero = field.ValueOf(stmt.ReflectValue); isZero {
+				if values.Values[0][idx], isZero = field.ValueOf(stmt.Context, stmt.ReflectValue); isZero {
 					if field.DefaultValueInterface != nil {
 						values.Values[0][idx] = field.DefaultValueInterface
-						field.Set(stmt.ReflectValue, field.DefaultValueInterface)
+						field.Set(stmt.Context, stmt.ReflectValue, field.DefaultValueInterface)
 					} else if field.AutoCreateTime > 0 || field.AutoUpdateTime > 0 {
-						field.Set(stmt.ReflectValue, curTime)
-						values.Values[0][idx], _ = field.ValueOf(stmt.ReflectValue)
+						field.Set(stmt.Context, stmt.ReflectValue, curTime)
+						values.Values[0][idx], _ = field.ValueOf(stmt.Context, stmt.ReflectValue)
 					}
 				} else if field.AutoUpdateTime > 0 && updateTrackTime {
-					field.Set(stmt.ReflectValue, curTime)
-					values.Values[0][idx], _ = field.ValueOf(stmt.ReflectValue)
+					field.Set(stmt.Context, stmt.ReflectValue, curTime)
+					values.Values[0][idx], _ = field.ValueOf(stmt.Context, stmt.ReflectValue)
 				}
 			}
 
 			for _, field := range stmt.Schema.FieldsWithDefaultDBValue {
 				if v, ok := selectColumns[field.DBName]; (ok && v) || (!ok && !restricted) {
-					if rvOfvalue, isZero := field.ValueOf(stmt.ReflectValue); !isZero {
+					if rvOfvalue, isZero := field.ValueOf(stmt.Context, stmt.ReflectValue); !isZero {
 						values.Columns = append(values.Columns, clause.Column{Name: field.DBName})
 						values.Values[0] = append(values.Values[0], rvOfvalue)
 					}
diff --git a/callbacks/delete.go b/callbacks/delete.go
index 7f1e09c..1fb5261 100644
--- a/callbacks/delete.go
+++ b/callbacks/delete.go
@@ -42,7 +42,7 @@ func DeleteBeforeAssociations(db *gorm.DB) {
 
 			switch rel.Type {
 			case schema.HasOne, schema.HasMany:
-				queryConds := rel.ToQueryConditions(db.Statement.ReflectValue)
+				queryConds := rel.ToQueryConditions(db.Statement.Context, db.Statement.ReflectValue)
 				modelValue := reflect.New(rel.FieldSchema.ModelType).Interface()
 				tx := db.Session(&gorm.Session{NewDB: true}).Model(modelValue)
 				withoutConditions := false
@@ -97,7 +97,7 @@ func DeleteBeforeAssociations(db *gorm.DB) {
 					}
 				}
 
-				_, foreignValues := schema.GetIdentityFieldValuesMap(db.Statement.ReflectValue, foreignFields)
+				_, foreignValues := schema.GetIdentityFieldValuesMap(db.Statement.Context, db.Statement.ReflectValue, foreignFields)
 				column, values := schema.ToQueryValues(table, relForeignKeys, foreignValues)
 				queryConds = append(queryConds, clause.IN{Column: column, Values: values})
 
@@ -123,7 +123,7 @@ func Delete(config *Config) func(db *gorm.DB) {
 			db.Statement.AddClauseIfNotExists(clause.Delete{})
 
 			if db.Statement.Schema != nil {
-				_, queryValues := schema.GetIdentityFieldValuesMap(db.Statement.ReflectValue, db.Statement.Schema.PrimaryFields)
+				_, queryValues := schema.GetIdentityFieldValuesMap(db.Statement.Context, db.Statement.ReflectValue, db.Statement.Schema.PrimaryFields)
 				column, values := schema.ToQueryValues(db.Statement.Table, db.Statement.Schema.PrimaryFieldDBNames, queryValues)
 
 				if len(values) > 0 {
@@ -131,7 +131,7 @@ func Delete(config *Config) func(db *gorm.DB) {
 				}
 
 				if db.Statement.ReflectValue.CanAddr() && db.Statement.Dest != db.Statement.Model && db.Statement.Model != nil {
-					_, queryValues = schema.GetIdentityFieldValuesMap(reflect.ValueOf(db.Statement.Model), db.Statement.Schema.PrimaryFields)
+					_, queryValues = schema.GetIdentityFieldValuesMap(db.Statement.Context, reflect.ValueOf(db.Statement.Model), db.Statement.Schema.PrimaryFields)
 					column, values = schema.ToQueryValues(db.Statement.Table, db.Statement.Schema.PrimaryFieldDBNames, queryValues)
 
 					if len(values) > 0 {
diff --git a/callbacks/preload.go b/callbacks/preload.go
index 41405a2..2363a8c 100644
--- a/callbacks/preload.go
+++ b/callbacks/preload.go
@@ -48,7 +48,7 @@ func preload(db *gorm.DB, rel *schema.Relationship, conds []interface{}, preload
 			}
 		}
 
-		joinIdentityMap, joinForeignValues := schema.GetIdentityFieldValuesMap(reflectValue, foreignFields)
+		joinIdentityMap, joinForeignValues := schema.GetIdentityFieldValuesMap(db.Statement.Context, reflectValue, foreignFields)
 		if len(joinForeignValues) == 0 {
 			return
 		}
@@ -63,11 +63,11 @@ func preload(db *gorm.DB, rel *schema.Relationship, conds []interface{}, preload
 		for i := 0; i < joinResults.Len(); i++ {
 			joinIndexValue := joinResults.Index(i)
 			for idx, field := range joinForeignFields {
-				fieldValues[idx], _ = field.ValueOf(joinIndexValue)
+				fieldValues[idx], _ = field.ValueOf(db.Statement.Context, joinIndexValue)
 			}
 
 			for idx, field := range joinRelForeignFields {
-				joinFieldValues[idx], _ = field.ValueOf(joinIndexValue)
+				joinFieldValues[idx], _ = field.ValueOf(db.Statement.Context, joinIndexValue)
 			}
 
 			if results, ok := joinIdentityMap[utils.ToStringKey(fieldValues...)]; ok {
@@ -76,7 +76,7 @@ func preload(db *gorm.DB, rel *schema.Relationship, conds []interface{}, preload
 			}
 		}
 
-		_, foreignValues = schema.GetIdentityFieldValuesMap(joinResults, joinRelForeignFields)
+		_, foreignValues = schema.GetIdentityFieldValuesMap(db.Statement.Context, joinResults, joinRelForeignFields)
 	} else {
 		for _, ref := range rel.References {
 			if ref.OwnPrimaryKey {
@@ -92,7 +92,7 @@ func preload(db *gorm.DB, rel *schema.Relationship, conds []interface{}, preload
 			}
 		}
 
-		identityMap, foreignValues = schema.GetIdentityFieldValuesMap(reflectValue, foreignFields)
+		identityMap, foreignValues = schema.GetIdentityFieldValuesMap(db.Statement.Context, reflectValue, foreignFields)
 		if len(foreignValues) == 0 {
 			return
 		}
@@ -125,17 +125,17 @@ func preload(db *gorm.DB, rel *schema.Relationship, conds []interface{}, preload
 	case reflect.Struct:
 		switch rel.Type {
 		case schema.HasMany, schema.Many2Many:
-			rel.Field.Set(reflectValue, reflect.MakeSlice(rel.Field.IndirectFieldType, 0, 10).Interface())
+			rel.Field.Set(db.Statement.Context, reflectValue, reflect.MakeSlice(rel.Field.IndirectFieldType, 0, 10).Interface())
 		default:
-			rel.Field.Set(reflectValue, reflect.New(rel.Field.FieldType).Interface())
+			rel.Field.Set(db.Statement.Context, reflectValue, reflect.New(rel.Field.FieldType).Interface())
 		}
 	case reflect.Slice, reflect.Array:
 		for i := 0; i < reflectValue.Len(); i++ {
 			switch rel.Type {
 			case schema.HasMany, schema.Many2Many:
-				rel.Field.Set(reflectValue.Index(i), reflect.MakeSlice(rel.Field.IndirectFieldType, 0, 10).Interface())
+				rel.Field.Set(db.Statement.Context, reflectValue.Index(i), reflect.MakeSlice(rel.Field.IndirectFieldType, 0, 10).Interface())
 			default:
-				rel.Field.Set(reflectValue.Index(i), reflect.New(rel.Field.FieldType).Interface())
+				rel.Field.Set(db.Statement.Context, reflectValue.Index(i), reflect.New(rel.Field.FieldType).Interface())
 			}
 		}
 	}
@@ -143,7 +143,7 @@ func preload(db *gorm.DB, rel *schema.Relationship, conds []interface{}, preload
 	for i := 0; i < reflectResults.Len(); i++ {
 		elem := reflectResults.Index(i)
 		for idx, field := range relForeignFields {
-			fieldValues[idx], _ = field.ValueOf(elem)
+			fieldValues[idx], _ = field.ValueOf(db.Statement.Context, elem)
 		}
 
 		datas, ok := identityMap[utils.ToStringKey(fieldValues...)]
@@ -154,7 +154,7 @@ func preload(db *gorm.DB, rel *schema.Relationship, conds []interface{}, preload
 		}
 
 		for _, data := range datas {
-			reflectFieldValue := rel.Field.ReflectValueOf(data)
+			reflectFieldValue := rel.Field.ReflectValueOf(db.Statement.Context, data)
 			if reflectFieldValue.Kind() == reflect.Ptr && reflectFieldValue.IsNil() {
 				reflectFieldValue.Set(reflect.New(rel.Field.FieldType.Elem()))
 			}
@@ -162,12 +162,12 @@ func preload(db *gorm.DB, rel *schema.Relationship, conds []interface{}, preload
 			reflectFieldValue = reflect.Indirect(reflectFieldValue)
 			switch reflectFieldValue.Kind() {
 			case reflect.Struct:
-				rel.Field.Set(data, elem.Interface())
+				rel.Field.Set(db.Statement.Context, data, elem.Interface())
 			case reflect.Slice, reflect.Array:
 				if reflectFieldValue.Type().Elem().Kind() == reflect.Ptr {
-					rel.Field.Set(data, reflect.Append(reflectFieldValue, elem).Interface())
+					rel.Field.Set(db.Statement.Context, data, reflect.Append(reflectFieldValue, elem).Interface())
 				} else {
-					rel.Field.Set(data, reflect.Append(reflectFieldValue, elem.Elem()).Interface())
+					rel.Field.Set(db.Statement.Context, data, reflect.Append(reflectFieldValue, elem.Elem()).Interface())
 				}
 			}
 		}
diff --git a/callbacks/query.go b/callbacks/query.go
index 4908635..0379885 100644
--- a/callbacks/query.go
+++ b/callbacks/query.go
@@ -40,7 +40,7 @@ func BuildQuerySQL(db *gorm.DB) {
 		if db.Statement.ReflectValue.Kind() == reflect.Struct && db.Statement.ReflectValue.Type() == db.Statement.Schema.ModelType {
 			var conds []clause.Expression
 			for _, primaryField := range db.Statement.Schema.PrimaryFields {
-				if v, isZero := primaryField.ValueOf(db.Statement.ReflectValue); !isZero {
+				if v, isZero := primaryField.ValueOf(db.Statement.Context, db.Statement.ReflectValue); !isZero {
 					conds = append(conds, clause.Eq{Column: clause.Column{Table: db.Statement.Table, Name: primaryField.DBName}, Value: v})
 				}
 			}
diff --git a/callbacks/update.go b/callbacks/update.go
index 511e994..4f07ca3 100644
--- a/callbacks/update.go
+++ b/callbacks/update.go
@@ -21,7 +21,7 @@ func SetupUpdateReflectValue(db *gorm.DB) {
 			if dest, ok := db.Statement.Dest.(map[string]interface{}); ok {
 				for _, rel := range db.Statement.Schema.Relationships.BelongsTo {
 					if _, ok := dest[rel.Name]; ok {
-						rel.Field.Set(db.Statement.ReflectValue, dest[rel.Name])
+						rel.Field.Set(db.Statement.Context, db.Statement.ReflectValue, dest[rel.Name])
 					}
 				}
 			}
@@ -137,13 +137,13 @@ func ConvertToAssignments(stmt *gorm.Statement) (set clause.Set) {
 	case reflect.Slice, reflect.Array:
 		assignValue = func(field *schema.Field, value interface{}) {
 			for i := 0; i < stmt.ReflectValue.Len(); i++ {
-				field.Set(stmt.ReflectValue.Index(i), value)
+				field.Set(stmt.Context, stmt.ReflectValue.Index(i), value)
 			}
 		}
 	case reflect.Struct:
 		assignValue = func(field *schema.Field, value interface{}) {
 			if stmt.ReflectValue.CanAddr() {
-				field.Set(stmt.ReflectValue, value)
+				field.Set(stmt.Context, stmt.ReflectValue, value)
 			}
 		}
 	default:
@@ -165,7 +165,7 @@ func ConvertToAssignments(stmt *gorm.Statement) (set clause.Set) {
 					exprs := make([]clause.Expression, len(stmt.Schema.PrimaryFields))
 					var notZero bool
 					for idx, field := range stmt.Schema.PrimaryFields {
-						value, isZero := field.ValueOf(stmt.ReflectValue.Index(i))
+						value, isZero := field.ValueOf(stmt.Context, stmt.ReflectValue.Index(i))
 						exprs[idx] = clause.Eq{Column: field.DBName, Value: value}
 						notZero = notZero || !isZero
 					}
@@ -178,7 +178,7 @@ func ConvertToAssignments(stmt *gorm.Statement) (set clause.Set) {
 			}
 		case reflect.Struct:
 			for _, field := range stmt.Schema.PrimaryFields {
-				if value, isZero := field.ValueOf(stmt.ReflectValue); !isZero {
+				if value, isZero := field.ValueOf(stmt.Context, stmt.ReflectValue); !isZero {
 					stmt.AddClause(clause.Where{Exprs: []clause.Expression{clause.Eq{Column: field.DBName, Value: value}}})
 				}
 			}
@@ -258,7 +258,7 @@ func ConvertToAssignments(stmt *gorm.Statement) (set clause.Set) {
 				if field := updatingSchema.LookUpField(dbName); field != nil {
 					if !field.PrimaryKey || !updatingValue.CanAddr() || stmt.Dest != stmt.Model {
 						if v, ok := selectColumns[field.DBName]; (ok && v) || (!ok && (!restricted || (!stmt.SkipHooks && field.AutoUpdateTime > 0))) {
-							value, isZero := field.ValueOf(updatingValue)
+							value, isZero := field.ValueOf(stmt.Context, updatingValue)
 							if !stmt.SkipHooks && field.AutoUpdateTime > 0 {
 								if field.AutoUpdateTime == schema.UnixNanosecond {
 									value = stmt.DB.NowFunc().UnixNano()
@@ -278,7 +278,7 @@ func ConvertToAssignments(stmt *gorm.Statement) (set clause.Set) {
 							}
 						}
 					} else {
-						if value, isZero := field.ValueOf(updatingValue); !isZero {
+						if value, isZero := field.ValueOf(stmt.Context, updatingValue); !isZero {
 							stmt.AddClause(clause.Where{Exprs: []clause.Expression{clause.Eq{Column: field.DBName, Value: value}}})
 						}
 					}
diff --git a/finisher_api.go b/finisher_api.go
index 3a17997..d2a8b98 100644
--- a/finisher_api.go
+++ b/finisher_api.go
@@ -83,7 +83,7 @@ func (db *DB) Save(value interface{}) (tx *DB) {
 	case reflect.Struct:
 		if err := tx.Statement.Parse(value); err == nil && tx.Statement.Schema != nil {
 			for _, pf := range tx.Statement.Schema.PrimaryFields {
-				if _, isZero := pf.ValueOf(reflectValue); isZero {
+				if _, isZero := pf.ValueOf(tx.Statement.Context, reflectValue); isZero {
 					return tx.callbacks.Create().Execute(tx)
 				}
 			}
@@ -199,7 +199,7 @@ func (db *DB) FindInBatches(dest interface{}, batchSize int, fc func(tx *DB, bat
 			break
 		}
 
-		primaryValue, _ := result.Statement.Schema.PrioritizedPrimaryField.ValueOf(resultsValue.Index(resultsValue.Len() - 1))
+		primaryValue, _ := result.Statement.Schema.PrioritizedPrimaryField.ValueOf(tx.Statement.Context, resultsValue.Index(resultsValue.Len()-1))
 		queryDB = tx.Clauses(clause.Gt{Column: clause.Column{Table: clause.CurrentTable, Name: clause.PrimaryKey}, Value: primaryValue})
 	}
 
@@ -216,11 +216,11 @@ func (tx *DB) assignInterfacesToValue(values ...interface{}) {
 					switch column := eq.Column.(type) {
 					case string:
 						if field := tx.Statement.Schema.LookUpField(column); field != nil {
-							tx.AddError(field.Set(tx.Statement.ReflectValue, eq.Value))
+							tx.AddError(field.Set(tx.Statement.Context, tx.Statement.ReflectValue, eq.Value))
 						}
 					case clause.Column:
 						if field := tx.Statement.Schema.LookUpField(column.Name); field != nil {
-							tx.AddError(field.Set(tx.Statement.ReflectValue, eq.Value))
+							tx.AddError(field.Set(tx.Statement.Context, tx.Statement.ReflectValue, eq.Value))
 						}
 					}
 				} else if andCond, ok := expr.(clause.AndConditions); ok {
@@ -238,9 +238,9 @@ func (tx *DB) assignInterfacesToValue(values ...interface{}) {
 				case reflect.Struct:
 					for _, f := range s.Fields {
 						if f.Readable {
-							if v, isZero := f.ValueOf(reflectValue); !isZero {
+							if v, isZero := f.ValueOf(tx.Statement.Context, reflectValue); !isZero {
 								if field := tx.Statement.Schema.LookUpField(f.Name); field != nil {
-									tx.AddError(field.Set(tx.Statement.ReflectValue, v))
+									tx.AddError(field.Set(tx.Statement.Context, tx.Statement.ReflectValue, v))
 								}
 							}
 						}
diff --git a/interfaces.go b/interfaces.go
index 44b2fce..ff0ca60 100644
--- a/interfaces.go
+++ b/interfaces.go
@@ -40,14 +40,17 @@ type SavePointerDialectorInterface interface {
 	RollbackTo(tx *DB, name string) error
 }
 
+// TxBeginner tx beginner
 type TxBeginner interface {
 	BeginTx(ctx context.Context, opts *sql.TxOptions) (*sql.Tx, error)
 }
 
+// ConnPoolBeginner conn pool beginner
 type ConnPoolBeginner interface {
 	BeginTx(ctx context.Context, opts *sql.TxOptions) (ConnPool, error)
 }
 
+// TxCommitter tx commiter
 type TxCommitter interface {
 	Commit() error
 	Rollback() error
@@ -58,6 +61,7 @@ type Valuer interface {
 	GormValue(context.Context, *DB) clause.Expr
 }
 
+// GetDBConnector SQL db connector
 type GetDBConnector interface {
 	GetDBConn() (*sql.DB, error)
 }
diff --git a/migrator.go b/migrator.go
index 2a8b425..5244387 100644
--- a/migrator.go
+++ b/migrator.go
@@ -1,6 +1,8 @@
 package gorm
 
 import (
+	"reflect"
+
 	"gorm.io/gorm/clause"
 	"gorm.io/gorm/schema"
 )
@@ -33,14 +35,23 @@ type ViewOption struct {
 	Query       *DB
 }
 
+// ColumnType column type interface
 type ColumnType interface {
 	Name() string
-	DatabaseTypeName() string
+	DatabaseTypeName() string                 // varchar
+	ColumnType() (columnType string, ok bool) // varchar(64)
+	PrimaryKey() (isPrimaryKey bool, ok bool)
+	AutoIncrement() (isAutoIncrement bool, ok bool)
 	Length() (length int64, ok bool)
 	DecimalSize() (precision int64, scale int64, ok bool)
 	Nullable() (nullable bool, ok bool)
+	Unique() (unique bool, ok bool)
+	ScanType() reflect.Type
+	Comment() (value string, ok bool)
+	DefaultValue() (value string, ok bool)
 }
 
+// Migrator migrator interface
 type Migrator interface {
 	// AutoMigrate
 	AutoMigrate(dst ...interface{}) error
diff --git a/migrator/column_type.go b/migrator/column_type.go
new file mode 100644
index 0000000..eb8d1b7
--- /dev/null
+++ b/migrator/column_type.go
@@ -0,0 +1,107 @@
+package migrator
+
+import (
+	"database/sql"
+	"reflect"
+)
+
+// ColumnType column type implements ColumnType interface
+type ColumnType struct {
+	SQLColumnType      *sql.ColumnType
+	NameValue          sql.NullString
+	DataTypeValue      sql.NullString
+	ColumnTypeValue    sql.NullString
+	PrimayKeyValue     sql.NullBool
+	UniqueValue        sql.NullBool
+	AutoIncrementValue sql.NullBool
+	LengthValue        sql.NullInt64
+	DecimalSizeValue   sql.NullInt64
+	ScaleValue         sql.NullInt64
+	NullableValue      sql.NullBool
+	ScanTypeValue      reflect.Type
+	CommentValue       sql.NullString
+	DefaultValueValue  sql.NullString
+}
+
+// Name returns the name or alias of the column.
+func (ct ColumnType) Name() string {
+	if ct.NameValue.Valid {
+		return ct.NameValue.String
+	}
+	return ct.SQLColumnType.Name()
+}
+
+// DatabaseTypeName returns the database system name of the column type. If an empty
+// string is returned, then the driver type name is not supported.
+// Consult your driver documentation for a list of driver data types. Length specifiers
+// are not included.
+// Common type names include "VARCHAR", "TEXT", "NVARCHAR", "DECIMAL", "BOOL",
+// "INT", and "BIGINT".
+func (ct ColumnType) DatabaseTypeName() string {
+	if ct.DataTypeValue.Valid {
+		return ct.DataTypeValue.String
+	}
+	return ct.SQLColumnType.DatabaseTypeName()
+}
+
+// ColumnType returns the database type of the column. lke `varchar(16)`
+func (ct ColumnType) ColumnType() (columnType string, ok bool) {
+	return ct.ColumnTypeValue.String, ct.ColumnTypeValue.Valid
+}
+
+// PrimaryKey returns the column is primary key or not.
+func (ct ColumnType) PrimaryKey() (isPrimaryKey bool, ok bool) {
+	return ct.PrimayKeyValue.Bool, ct.PrimayKeyValue.Valid
+}
+
+// AutoIncrement returns the column is auto increment or not.
+func (ct ColumnType) AutoIncrement() (isAutoIncrement bool, ok bool) {
+	return ct.AutoIncrementValue.Bool, ct.AutoIncrementValue.Valid
+}
+
+// Length returns the column type length for variable length column types
+func (ct ColumnType) Length() (length int64, ok bool) {
+	if ct.LengthValue.Valid {
+		return ct.LengthValue.Int64, true
+	}
+	return ct.SQLColumnType.Length()
+}
+
+// DecimalSize returns the scale and precision of a decimal type.
+func (ct ColumnType) DecimalSize() (precision int64, scale int64, ok bool) {
+	if ct.DecimalSizeValue.Valid {
+		return ct.DecimalSizeValue.Int64, ct.ScaleValue.Int64, true
+	}
+	return ct.SQLColumnType.DecimalSize()
+}
+
+// Nullable reports whether the column may be null.
+func (ct ColumnType) Nullable() (nullable bool, ok bool) {
+	if ct.NullableValue.Valid {
+		return ct.NullableValue.Bool, true
+	}
+	return ct.SQLColumnType.Nullable()
+}
+
+// Unique reports whether the column may be unique.
+func (ct ColumnType) Unique() (unique bool, ok bool) {
+	return ct.UniqueValue.Bool, ct.UniqueValue.Valid
+}
+
+// ScanType returns a Go type suitable for scanning into using Rows.Scan.
+func (ct ColumnType) ScanType() reflect.Type {
+	if ct.ScanTypeValue != nil {
+		return ct.ScanTypeValue
+	}
+	return ct.SQLColumnType.ScanType()
+}
+
+// Comment returns the comment of current column.
+func (ct ColumnType) Comment() (value string, ok bool) {
+	return ct.CommentValue.String, ct.CommentValue.Valid
+}
+
+// DefaultValue returns the default value of current column.
+func (ct ColumnType) DefaultValue() (value string, ok bool) {
+	return ct.DefaultValueValue.String, ct.DefaultValueValue.Valid
+}
diff --git a/migrator/migrator.go b/migrator/migrator.go
index 80c4e2b..9695f31 100644
--- a/migrator/migrator.go
+++ b/migrator/migrator.go
@@ -30,10 +30,12 @@ type Config struct {
 	gorm.Dialector
 }
 
+// GormDataTypeInterface gorm data type interface
 type GormDataTypeInterface interface {
 	GormDBDataType(*gorm.DB, *schema.Field) string
 }
 
+// RunWithValue run migration with statement value
 func (m Migrator) RunWithValue(value interface{}, fc func(*gorm.Statement) error) error {
 	stmt := &gorm.Statement{DB: m.DB}
 	if m.DB.Statement != nil {
@@ -50,6 +52,7 @@ func (m Migrator) RunWithValue(value interface{}, fc func(*gorm.Statement) error
 	return fc(stmt)
 }
 
+// DataTypeOf return field's db data type
 func (m Migrator) DataTypeOf(field *schema.Field) string {
 	fieldValue := reflect.New(field.IndirectFieldType)
 	if dataTyper, ok := fieldValue.Interface().(GormDataTypeInterface); ok {
@@ -61,6 +64,7 @@ func (m Migrator) DataTypeOf(field *schema.Field) string {
 	return m.Dialector.DataTypeOf(field)
 }
 
+// FullDataTypeOf returns field's db full data type
 func (m Migrator) FullDataTypeOf(field *schema.Field) (expr clause.Expr) {
 	expr.SQL = m.DataTypeOf(field)
 
@@ -85,7 +89,7 @@ func (m Migrator) FullDataTypeOf(field *schema.Field) (expr clause.Expr) {
 	return
 }
 
-// AutoMigrate
+// AutoMigrate auto migrate values
 func (m Migrator) AutoMigrate(values ...interface{}) error {
 	for _, value := range m.ReorderModels(values, true) {
 		tx := m.DB.Session(&gorm.Session{})
@@ -156,12 +160,14 @@ func (m Migrator) AutoMigrate(values ...interface{}) error {
 	return nil
 }
 
+// GetTables returns tables
 func (m Migrator) GetTables() (tableList []string, err error) {
 	err = m.DB.Raw("SELECT TABLE_NAME FROM information_schema.tables where TABLE_SCHEMA=?", m.CurrentDatabase()).
 		Scan(&tableList).Error
 	return
 }
 
+// CreateTable create table in database for values
 func (m Migrator) CreateTable(values ...interface{}) error {
 	for _, value := range m.ReorderModels(values, false) {
 		tx := m.DB.Session(&gorm.Session{})
@@ -252,6 +258,7 @@ func (m Migrator) CreateTable(values ...interface{}) error {
 	return nil
 }
 
+// DropTable drop table for values
 func (m Migrator) DropTable(values ...interface{}) error {
 	values = m.ReorderModels(values, false)
 	for i := len(values) - 1; i >= 0; i-- {
@@ -265,6 +272,7 @@ func (m Migrator) DropTable(values ...interface{}) error {
 	return nil
 }
 
+// HasTable returns table exists or not for value, value could be a struct or string
 func (m Migrator) HasTable(value interface{}) bool {
 	var count int64
 
@@ -276,6 +284,7 @@ func (m Migrator) HasTable(value interface{}) bool {
 	return count > 0
 }
 
+// RenameTable rename table from oldName to newName
 func (m Migrator) RenameTable(oldName, newName interface{}) error {
 	var oldTable, newTable interface{}
 	if v, ok := oldName.(string); ok {
@@ -303,12 +312,13 @@ func (m Migrator) RenameTable(oldName, newName interface{}) error {
 	return m.DB.Exec("ALTER TABLE ? RENAME TO ?", oldTable, newTable).Error
 }
 
-func (m Migrator) AddColumn(value interface{}, field string) error {
+// AddColumn create `name` column for value
+func (m Migrator) AddColumn(value interface{}, name string) error {
 	return m.RunWithValue(value, func(stmt *gorm.Statement) error {
 		// avoid using the same name field
-		f := stmt.Schema.LookUpField(field)
+		f := stmt.Schema.LookUpField(name)
 		if f == nil {
-			return fmt.Errorf("failed to look up field with name: %s", field)
+			return fmt.Errorf("failed to look up field with name: %s", name)
 		}
 
 		if !f.IgnoreMigration {
@@ -322,6 +332,7 @@ func (m Migrator) AddColumn(value interface{}, field string) error {
 	})
 }
 
+// DropColumn drop value's `name` column
 func (m Migrator) DropColumn(value interface{}, name string) error {
 	return m.RunWithValue(value, func(stmt *gorm.Statement) error {
 		if field := stmt.Schema.LookUpField(name); field != nil {
@@ -334,6 +345,7 @@ func (m Migrator) DropColumn(value interface{}, name string) error {
 	})
 }
 
+// AlterColumn alter value's `field` column' type based on schema definition
 func (m Migrator) AlterColumn(value interface{}, field string) error {
 	return m.RunWithValue(value, func(stmt *gorm.Statement) error {
 		if field := stmt.Schema.LookUpField(field); field != nil {
@@ -348,6 +360,7 @@ func (m Migrator) AlterColumn(value interface{}, field string) error {
 	})
 }
 
+// HasColumn check has column `field` for value or not
 func (m Migrator) HasColumn(value interface{}, field string) bool {
 	var count int64
 	m.RunWithValue(value, func(stmt *gorm.Statement) error {
@@ -366,6 +379,7 @@ func (m Migrator) HasColumn(value interface{}, field string) bool {
 	return count > 0
 }
 
+// RenameColumn rename value's field name from oldName to newName
 func (m Migrator) RenameColumn(value interface{}, oldName, newName string) error {
 	return m.RunWithValue(value, func(stmt *gorm.Statement) error {
 		if field := stmt.Schema.LookUpField(oldName); field != nil {
@@ -383,6 +397,7 @@ func (m Migrator) RenameColumn(value interface{}, oldName, newName string) error
 	})
 }
 
+// MigrateColumn migrate column
 func (m Migrator) MigrateColumn(value interface{}, field *schema.Field, columnType gorm.ColumnType) error {
 	// found, smart migrate
 	fullDataType := strings.ToLower(m.DB.Migrator().FullDataTypeOf(field).SQL)
@@ -448,7 +463,7 @@ func (m Migrator) ColumnTypes(value interface{}) ([]gorm.ColumnType, error) {
 		}
 
 		for _, c := range rawColumnTypes {
-			columnTypes = append(columnTypes, c)
+			columnTypes = append(columnTypes, ColumnType{SQLColumnType: c})
 		}
 
 		return
@@ -457,10 +472,12 @@ func (m Migrator) ColumnTypes(value interface{}) ([]gorm.ColumnType, error) {
 	return columnTypes, execErr
 }
 
+// CreateView create view
 func (m Migrator) CreateView(name string, option gorm.ViewOption) error {
 	return gorm.ErrNotImplemented
 }
 
+// DropView drop view
 func (m Migrator) DropView(name string) error {
 	return gorm.ErrNotImplemented
 }
@@ -487,6 +504,7 @@ func buildConstraint(constraint *schema.Constraint) (sql string, results []inter
 	return
 }
 
+// GuessConstraintAndTable guess statement's constraint and it's table based on name
 func (m Migrator) GuessConstraintAndTable(stmt *gorm.Statement, name string) (_ *schema.Constraint, _ *schema.Check, table string) {
 	if stmt.Schema == nil {
 		return nil, nil, stmt.Table
@@ -531,6 +549,7 @@ func (m Migrator) GuessConstraintAndTable(stmt *gorm.Statement, name string) (_
 	return nil, nil, stmt.Schema.Table
 }
 
+// CreateConstraint create constraint
 func (m Migrator) CreateConstraint(value interface{}, name string) error {
 	return m.RunWithValue(value, func(stmt *gorm.Statement) error {
 		constraint, chk, table := m.GuessConstraintAndTable(stmt, name)
@@ -554,6 +573,7 @@ func (m Migrator) CreateConstraint(value interface{}, name string) error {
 	})
 }
 
+// DropConstraint drop constraint
 func (m Migrator) DropConstraint(value interface{}, name string) error {
 	return m.RunWithValue(value, func(stmt *gorm.Statement) error {
 		constraint, chk, table := m.GuessConstraintAndTable(stmt, name)
@@ -566,6 +586,7 @@ func (m Migrator) DropConstraint(value interface{}, name string) error {
 	})
 }
 
+// HasConstraint check has constraint or not
 func (m Migrator) HasConstraint(value interface{}, name string) bool {
 	var count int64
 	m.RunWithValue(value, func(stmt *gorm.Statement) error {
@@ -586,6 +607,7 @@ func (m Migrator) HasConstraint(value interface{}, name string) bool {
 	return count > 0
 }
 
+// BuildIndexOptions build index options
 func (m Migrator) BuildIndexOptions(opts []schema.IndexOption, stmt *gorm.Statement) (results []interface{}) {
 	for _, opt := range opts {
 		str := stmt.Quote(opt.DBName)
@@ -607,10 +629,12 @@ func (m Migrator) BuildIndexOptions(opts []schema.IndexOption, stmt *gorm.Statem
 	return
 }
 
+// BuildIndexOptionsInterface build index options interface
 type BuildIndexOptionsInterface interface {
 	BuildIndexOptions([]schema.IndexOption, *gorm.Statement) []interface{}
 }
 
+// CreateIndex create index `name`
 func (m Migrator) CreateIndex(value interface{}, name string) error {
 	return m.RunWithValue(value, func(stmt *gorm.Statement) error {
 		if idx := stmt.Schema.LookIndex(name); idx != nil {
@@ -642,6 +666,7 @@ func (m Migrator) CreateIndex(value interface{}, name string) error {
 	})
 }
 
+// DropIndex drop index `name`
 func (m Migrator) DropIndex(value interface{}, name string) error {
 	return m.RunWithValue(value, func(stmt *gorm.Statement) error {
 		if idx := stmt.Schema.LookIndex(name); idx != nil {
@@ -652,6 +677,7 @@ func (m Migrator) DropIndex(value interface{}, name string) error {
 	})
 }
 
+// HasIndex check has index `name` or not
 func (m Migrator) HasIndex(value interface{}, name string) bool {
 	var count int64
 	m.RunWithValue(value, func(stmt *gorm.Statement) error {
@@ -669,6 +695,7 @@ func (m Migrator) HasIndex(value interface{}, name string) bool {
 	return count > 0
 }
 
+// RenameIndex rename index from oldName to newName
 func (m Migrator) RenameIndex(value interface{}, oldName, newName string) error {
 	return m.RunWithValue(value, func(stmt *gorm.Statement) error {
 		return m.DB.Exec(
@@ -678,6 +705,7 @@ func (m Migrator) RenameIndex(value interface{}, oldName, newName string) error
 	})
 }
 
+// CurrentDatabase returns current database name
 func (m Migrator) CurrentDatabase() (name string) {
 	m.DB.Raw("SELECT DATABASE()").Row().Scan(&name)
 	return
@@ -781,6 +809,7 @@ func (m Migrator) ReorderModels(values []interface{}, autoAdd bool) (results []i
 	return
 }
 
+// CurrentTable returns current statement's table expression
 func (m Migrator) CurrentTable(stmt *gorm.Statement) interface{} {
 	if stmt.TableExpr != nil {
 		return *stmt.TableExpr
diff --git a/scan.go b/scan.go
index b03b79b..0da12da 100644
--- a/scan.go
+++ b/scan.go
@@ -10,6 +10,7 @@ import (
 	"gorm.io/gorm/schema"
 )
 
+// prepareValues prepare values slice
 func prepareValues(values []interface{}, db *DB, columnTypes []*sql.ColumnType, columns []string) {
 	if db.Statement.Schema != nil {
 		for idx, name := range columns {
@@ -54,11 +55,13 @@ func (db *DB) scanIntoStruct(sch *schema.Schema, rows *sql.Rows, reflectValue re
 		if sch == nil {
 			values[idx] = reflectValue.Interface()
 		} else if field := sch.LookUpField(column); field != nil && field.Readable {
-			values[idx] = reflect.New(reflect.PtrTo(field.IndirectFieldType)).Interface()
+			values[idx] = field.NewValuePool.Get()
+			defer field.NewValuePool.Put(values[idx])
 		} else if names := strings.Split(column, "__"); len(names) > 1 {
 			if rel, ok := sch.Relationships.Relations[names[0]]; ok {
 				if field := rel.FieldSchema.LookUpField(strings.Join(names[1:], "__")); field != nil && field.Readable {
-					values[idx] = reflect.New(reflect.PtrTo(field.IndirectFieldType)).Interface()
+					values[idx] = field.NewValuePool.Get()
+					defer field.NewValuePool.Put(values[idx])
 					continue
 				}
 			}
@@ -77,21 +80,21 @@ func (db *DB) scanIntoStruct(sch *schema.Schema, rows *sql.Rows, reflectValue re
 	if sch != nil {
 		for idx, column := range columns {
 			if field := sch.LookUpField(column); field != nil && field.Readable {
-				field.Set(reflectValue, values[idx])
+				field.Set(db.Statement.Context, reflectValue, values[idx])
 			} else if names := strings.Split(column, "__"); len(names) > 1 {
 				if rel, ok := sch.Relationships.Relations[names[0]]; ok {
 					if field := rel.FieldSchema.LookUpField(strings.Join(names[1:], "__")); field != nil && field.Readable {
-						relValue := rel.Field.ReflectValueOf(reflectValue)
-						value := reflect.ValueOf(values[idx]).Elem()
+						relValue := rel.Field.ReflectValueOf(db.Statement.Context, reflectValue)
 
 						if relValue.Kind() == reflect.Ptr && relValue.IsNil() {
-							if value.IsNil() {
+							if value := reflect.ValueOf(values[idx]).Elem(); value.Kind() == reflect.Ptr && value.IsNil() {
 								continue
 							}
+
 							relValue.Set(reflect.New(relValue.Type().Elem()))
 						}
 
-						field.Set(relValue, values[idx])
+						field.Set(db.Statement.Context, relValue, values[idx])
 					}
 				}
 			}
@@ -99,14 +102,17 @@ func (db *DB) scanIntoStruct(sch *schema.Schema, rows *sql.Rows, reflectValue re
 	}
 }
 
+// ScanMode scan data mode
 type ScanMode uint8
 
+// scan modes
 const (
 	ScanInitialized         ScanMode = 1 << 0 // 1
 	ScanUpdate              ScanMode = 1 << 1 // 2
 	ScanOnConflictDoNothing ScanMode = 1 << 2 // 4
 )
 
+// Scan scan rows into db statement
 func Scan(rows *sql.Rows, db *DB, mode ScanMode) {
 	var (
 		columns, _          = rows.Columns()
@@ -138,7 +144,7 @@ func Scan(rows *sql.Rows, db *DB, mode ScanMode) {
 			}
 			scanIntoMap(mapValue, values, columns)
 		}
-	case *[]map[string]interface{}, []map[string]interface{}:
+	case *[]map[string]interface{}:
 		columnTypes, _ := rows.ColumnTypes()
 		for initialized || rows.Next() {
 			prepareValues(values, db, columnTypes, columns)
@@ -149,11 +155,7 @@ func Scan(rows *sql.Rows, db *DB, mode ScanMode) {
 
 			mapValue := map[string]interface{}{}
 			scanIntoMap(mapValue, values, columns)
-			if values, ok := dest.([]map[string]interface{}); ok {
-				values = append(values, mapValue)
-			} else if values, ok := dest.(*[]map[string]interface{}); ok {
-				*values = append(*values, mapValue)
-			}
+			*dest = append(*dest, mapValue)
 		}
 	case *int, *int8, *int16, *int32, *int64,
 		*uint, *uint8, *uint16, *uint32, *uint64, *uintptr,
@@ -174,7 +176,7 @@ func Scan(rows *sql.Rows, db *DB, mode ScanMode) {
 			reflectValue = db.Statement.ReflectValue
 		)
 
-		if reflectValue.Kind() == reflect.Interface {
+		for reflectValue.Kind() == reflect.Interface {
 			reflectValue = reflectValue.Elem()
 		}
 
@@ -244,7 +246,7 @@ func Scan(rows *sql.Rows, db *DB, mode ScanMode) {
 					elem = reflectValue.Index(int(db.RowsAffected))
 					if onConflictDonothing {
 						for _, field := range fields {
-							if _, ok := field.ValueOf(elem); !ok {
+							if _, ok := field.ValueOf(db.Statement.Context, elem); !ok {
 								db.RowsAffected++
 								goto BEGIN
 							}
diff --git a/schema/field.go b/schema/field.go
index 485bbdf..319f369 100644
--- a/schema/field.go
+++ b/schema/field.go
@@ -1,6 +1,7 @@
 package schema
 
 import (
+	"context"
 	"database/sql"
 	"database/sql/driver"
 	"fmt"
@@ -14,12 +15,21 @@ import (
 	"gorm.io/gorm/utils"
 )
 
-type DataType string
-
-type TimeType int64
+// special types' reflect type
+var (
+	TimeReflectType    = reflect.TypeOf(time.Time{})
+	TimePtrReflectType = reflect.TypeOf(&time.Time{})
+	ByteReflectType    = reflect.TypeOf(uint8(0))
+)
 
-var TimeReflectType = reflect.TypeOf(time.Time{})
+type (
+	// DataType GORM data type
+	DataType string
+	// TimeType GORM time type
+	TimeType int64
+)
 
+// GORM time types
 const (
 	UnixTime        TimeType = 1
 	UnixSecond      TimeType = 2
@@ -27,6 +37,7 @@ const (
 	UnixNanosecond  TimeType = 4
 )
 
+// GORM fields types
 const (
 	Bool   DataType = "bool"
 	Int    DataType = "int"
@@ -37,6 +48,7 @@ const (
 	Bytes  DataType = "bytes"
 )
 
+// Field is the representation of model schema's field
 type Field struct {
 	Name                   string
 	DBName                 string
@@ -49,9 +61,9 @@ type Field struct {
 	Creatable              bool
 	Updatable              bool
 	Readable               bool
-	HasDefaultValue        bool
 	AutoCreateTime         TimeType
 	AutoUpdateTime         TimeType
+	HasDefaultValue        bool
 	DefaultValue           string
 	DefaultValueInterface  interface{}
 	NotNull                bool
@@ -60,6 +72,7 @@ type Field struct {
 	Size                   int
 	Precision              int
 	Scale                  int
+	IgnoreMigration        bool
 	FieldType              reflect.Type
 	IndirectFieldType      reflect.Type
 	StructField            reflect.StructField
@@ -68,27 +81,39 @@ type Field struct {
 	Schema                 *Schema
 	EmbeddedSchema         *Schema
 	OwnerSchema            *Schema
-	ReflectValueOf         func(reflect.Value) reflect.Value
-	ValueOf                func(reflect.Value) (value interface{}, zero bool)
-	Set                    func(reflect.Value, interface{}) error
-	IgnoreMigration        bool
+	ReflectValueOf         func(context.Context, reflect.Value) reflect.Value
+	ValueOf                func(context.Context, reflect.Value) (value interface{}, zero bool)
+	Set                    func(context.Context, reflect.Value, interface{}) error
+	Serializer             SerializerInterface
+	NewValuePool           FieldNewValuePool
 }
 
+// ParseField parses reflect.StructField to Field
 func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
-	var err error
+	var (
+		err        error
+		tagSetting = ParseTagSetting(fieldStruct.Tag.Get("gorm"), ";")
+	)
 
 	field := &Field{
 		Name:                   fieldStruct.Name,
+		DBName:                 tagSetting["COLUMN"],
 		BindNames:              []string{fieldStruct.Name},
 		FieldType:              fieldStruct.Type,
 		IndirectFieldType:      fieldStruct.Type,
 		StructField:            fieldStruct,
+		Tag:                    fieldStruct.Tag,
+		TagSettings:            tagSetting,
+		Schema:                 schema,
 		Creatable:              true,
 		Updatable:              true,
 		Readable:               true,
-		Tag:                    fieldStruct.Tag,
-		TagSettings:            ParseTagSetting(fieldStruct.Tag.Get("gorm"), ";"),
-		Schema:                 schema,
+		PrimaryKey:             utils.CheckTruth(tagSetting["PRIMARYKEY"], tagSetting["PRIMARY_KEY"]),
+		AutoIncrement:          utils.CheckTruth(tagSetting["AUTOINCREMENT"]),
+		HasDefaultValue:        utils.CheckTruth(tagSetting["AUTOINCREMENT"]),
+		NotNull:                utils.CheckTruth(tagSetting["NOT NULL"], tagSetting["NOTNULL"]),
+		Unique:                 utils.CheckTruth(tagSetting["UNIQUE"]),
+		Comment:                tagSetting["COMMENT"],
 		AutoIncrementIncrement: 1,
 	}
 
@@ -97,7 +122,7 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
 	}
 
 	fieldValue := reflect.New(field.IndirectFieldType)
-	// if field is valuer, used its value or first fields as data type
+	// if field is valuer, used its value or first field as data type
 	valuer, isValuer := fieldValue.Interface().(driver.Valuer)
 	if isValuer {
 		if _, ok := fieldValue.Interface().(GormDataTypeInterface); !ok {
@@ -105,31 +130,37 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
 				fieldValue = reflect.ValueOf(v)
 			}
 
+			// Use the field struct's first field type as data type, e.g: use `string` for sql.NullString
 			var getRealFieldValue func(reflect.Value)
 			getRealFieldValue = func(v reflect.Value) {
-				rv := reflect.Indirect(v)
-				if rv.Kind() == reflect.Struct && !rv.Type().ConvertibleTo(TimeReflectType) {
-					for i := 0; i < rv.Type().NumField(); i++ {
-						newFieldType := rv.Type().Field(i).Type
+				var (
+					rv     = reflect.Indirect(v)
+					rvType = rv.Type()
+				)
+
+				if rv.Kind() == reflect.Struct && !rvType.ConvertibleTo(TimeReflectType) {
+					for i := 0; i < rvType.NumField(); i++ {
+						for key, value := range ParseTagSetting(rvType.Field(i).Tag.Get("gorm"), ";") {
+							if _, ok := field.TagSettings[key]; !ok {
+								field.TagSettings[key] = value
+							}
+						}
+					}
+
+					for i := 0; i < rvType.NumField(); i++ {
+						newFieldType := rvType.Field(i).Type
 						for newFieldType.Kind() == reflect.Ptr {
 							newFieldType = newFieldType.Elem()
 						}
 
 						fieldValue = reflect.New(newFieldType)
-
-						if rv.Type() != reflect.Indirect(fieldValue).Type() {
+						if rvType != reflect.Indirect(fieldValue).Type() {
 							getRealFieldValue(fieldValue)
 						}
 
 						if fieldValue.IsValid() {
 							return
 						}
-
-						for key, value := range ParseTagSetting(field.IndirectFieldType.Field(i).Tag.Get("gorm"), ";") {
-							if _, ok := field.TagSettings[key]; !ok {
-								field.TagSettings[key] = value
-							}
-						}
 					}
 				}
 			}
@@ -138,19 +169,23 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
 		}
 	}
 
-	if dbName, ok := field.TagSettings["COLUMN"]; ok {
-		field.DBName = dbName
-	}
-
-	if val, ok := field.TagSettings["PRIMARYKEY"]; ok && utils.CheckTruth(val) {
-		field.PrimaryKey = true
-	} else if val, ok := field.TagSettings["PRIMARY_KEY"]; ok && utils.CheckTruth(val) {
-		field.PrimaryKey = true
-	}
-
-	if val, ok := field.TagSettings["AUTOINCREMENT"]; ok && utils.CheckTruth(val) {
-		field.AutoIncrement = true
-		field.HasDefaultValue = true
+	if v, isSerializer := fieldValue.Interface().(SerializerInterface); isSerializer {
+		field.DataType = String
+		field.Serializer = v
+	} else {
+		var serializerName = field.TagSettings["JSON"]
+		if serializerName == "" {
+			serializerName = field.TagSettings["SERIALIZER"]
+		}
+		if serializerName != "" {
+			if serializer, ok := GetSerializer(serializerName); ok {
+				// Set default data type to string for serializer
+				field.DataType = String
+				field.Serializer = serializer
+			} else {
+				schema.err = fmt.Errorf("invalid serializer type %v", serializerName)
+			}
+		}
 	}
 
 	if num, ok := field.TagSettings["AUTOINCREMENTINCREMENT"]; ok {
@@ -176,20 +211,6 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
 		field.Scale, _ = strconv.Atoi(s)
 	}
 
-	if val, ok := field.TagSettings["NOT NULL"]; ok && utils.CheckTruth(val) {
-		field.NotNull = true
-	} else if val, ok := field.TagSettings["NOTNULL"]; ok && utils.CheckTruth(val) {
-		field.NotNull = true
-	}
-
-	if val, ok := field.TagSettings["UNIQUE"]; ok && utils.CheckTruth(val) {
-		field.Unique = true
-	}
-
-	if val, ok := field.TagSettings["COMMENT"]; ok {
-		field.Comment = val
-	}
-
 	// default value is function or null or blank (primary keys)
 	field.DefaultValue = strings.TrimSpace(field.DefaultValue)
 	skipParseDefaultValue := strings.Contains(field.DefaultValue, "(") &&
@@ -225,7 +246,6 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
 		}
 	case reflect.String:
 		field.DataType = String
-
 		if field.HasDefaultValue && !skipParseDefaultValue {
 			field.DefaultValue = strings.Trim(field.DefaultValue, "'")
 			field.DefaultValue = strings.Trim(field.DefaultValue, `"`)
@@ -236,17 +256,15 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
 			field.DataType = Time
 		} else if fieldValue.Type().ConvertibleTo(TimeReflectType) {
 			field.DataType = Time
-		} else if fieldValue.Type().ConvertibleTo(reflect.TypeOf(&time.Time{})) {
+		} else if fieldValue.Type().ConvertibleTo(TimePtrReflectType) {
 			field.DataType = Time
 		}
 	case reflect.Array, reflect.Slice:
-		if reflect.Indirect(fieldValue).Type().Elem() == reflect.TypeOf(uint8(0)) {
+		if reflect.Indirect(fieldValue).Type().Elem() == ByteReflectType && field.DataType == "" {
 			field.DataType = Bytes
 		}
 	}
 
-	field.GORMDataType = field.DataType
-
 	if dataTyper, ok := fieldValue.Interface().(GormDataTypeInterface); ok {
 		field.DataType = DataType(dataTyper.GormDataType())
 	}
@@ -346,8 +364,9 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
 		}
 	}
 
-	if _, ok := field.TagSettings["EMBEDDED"]; field.GORMDataType != Time && field.GORMDataType != Bytes &&
-		(ok || (fieldStruct.Anonymous && !isValuer && (field.Creatable || field.Updatable || field.Readable))) {
+	// Normal anonymous field or having `EMBEDDED` tag
+	if _, ok := field.TagSettings["EMBEDDED"]; ok || (field.GORMDataType != Time && field.GORMDataType != Bytes && !isValuer &&
+		fieldStruct.Anonymous && (field.Creatable || field.Updatable || field.Readable)) {
 		kind := reflect.Indirect(fieldValue).Kind()
 		switch kind {
 		case reflect.Struct:
@@ -410,95 +429,122 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
 
 // create valuer, setter when parse struct
 func (field *Field) setupValuerAndSetter() {
-	// ValueOf
-	switch {
-	case len(field.StructField.Index) == 1:
-		field.ValueOf = func(value reflect.Value) (interface{}, bool) {
-			fieldValue := reflect.Indirect(value).Field(field.StructField.Index[0])
-			return fieldValue.Interface(), fieldValue.IsZero()
-		}
-	case len(field.StructField.Index) == 2 && field.StructField.Index[0] >= 0:
-		field.ValueOf = func(value reflect.Value) (interface{}, bool) {
-			fieldValue := reflect.Indirect(value).Field(field.StructField.Index[0]).Field(field.StructField.Index[1])
-			return fieldValue.Interface(), fieldValue.IsZero()
+	// Setup NewValuePool
+	var fieldValue = reflect.New(field.FieldType).Interface()
+	if field.Serializer != nil {
+		field.NewValuePool = &sync.Pool{
+			New: func() interface{} {
+				return &serializer{
+					Field:      field,
+					Serializer: reflect.New(reflect.Indirect(reflect.ValueOf(field.Serializer)).Type()).Interface().(SerializerInterface),
+				}
+			},
 		}
-	default:
-		field.ValueOf = func(value reflect.Value) (interface{}, bool) {
-			v := reflect.Indirect(value)
+	} else if _, ok := fieldValue.(sql.Scanner); !ok {
+		// set default NewValuePool
+		switch field.IndirectFieldType.Kind() {
+		case reflect.String:
+			field.NewValuePool = stringPool
+		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+			field.NewValuePool = intPool
+		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+			field.NewValuePool = uintPool
+		case reflect.Float32, reflect.Float64:
+			field.NewValuePool = floatPool
+		case reflect.Bool:
+			field.NewValuePool = boolPool
+		default:
+			if field.IndirectFieldType == TimeReflectType {
+				field.NewValuePool = timePool
+			}
+		}
+	}
 
-			for _, idx := range field.StructField.Index {
-				if idx >= 0 {
-					v = v.Field(idx)
-				} else {
-					v = v.Field(-idx - 1)
+	if field.NewValuePool == nil {
+		field.NewValuePool = poolInitializer(reflect.PtrTo(field.IndirectFieldType))
+	}
 
-					if v.Type().Elem().Kind() != reflect.Struct {
-						return nil, true
-					}
+	// ValueOf returns field's value and if it is zero
+	field.ValueOf = func(ctx context.Context, v reflect.Value) (interface{}, bool) {
+		v = reflect.Indirect(v)
+		for _, fieldIdx := range field.StructField.Index {
+			if fieldIdx >= 0 {
+				v = v.Field(fieldIdx)
+			} else {
+				v = v.Field(-fieldIdx - 1)
 
-					if !v.IsNil() {
-						v = v.Elem()
-					} else {
-						return nil, true
-					}
+				if !v.IsNil() {
+					v = v.Elem()
+				} else {
+					return nil, true
 				}
 			}
-			return v.Interface(), v.IsZero()
 		}
+
+		fv, zero := v.Interface(), v.IsZero()
+		return fv, zero
 	}
 
-	// ReflectValueOf
-	switch {
-	case len(field.StructField.Index) == 1:
-		field.ReflectValueOf = func(value reflect.Value) reflect.Value {
-			return reflect.Indirect(value).Field(field.StructField.Index[0])
-		}
-	case len(field.StructField.Index) == 2 && field.StructField.Index[0] >= 0 && field.FieldType.Kind() != reflect.Ptr:
-		field.ReflectValueOf = func(value reflect.Value) reflect.Value {
-			return reflect.Indirect(value).Field(field.StructField.Index[0]).Field(field.StructField.Index[1])
+	if field.Serializer != nil {
+		oldValuerOf := field.ValueOf
+		field.ValueOf = func(ctx context.Context, v reflect.Value) (interface{}, bool) {
+			value, zero := oldValuerOf(ctx, v)
+			if zero {
+				return value, zero
+			}
+
+			s, ok := value.(SerializerValuerInterface)
+			if !ok {
+				s = field.Serializer
+			}
+
+			return serializer{
+				Field:           field,
+				SerializeValuer: s,
+				Destination:     v,
+				Context:         ctx,
+				fieldValue:      value,
+			}, false
 		}
-	default:
-		field.ReflectValueOf = func(value reflect.Value) reflect.Value {
-			v := reflect.Indirect(value)
-			for idx, fieldIdx := range field.StructField.Index {
-				if fieldIdx >= 0 {
-					v = v.Field(fieldIdx)
-				} else {
-					v = v.Field(-fieldIdx - 1)
-				}
+	}
 
-				if v.Kind() == reflect.Ptr {
-					if v.Type().Elem().Kind() == reflect.Struct {
-						if v.IsNil() {
-							v.Set(reflect.New(v.Type().Elem()))
-						}
-					}
+	// ReflectValueOf returns field's reflect value
+	field.ReflectValueOf = func(ctx context.Context, v reflect.Value) reflect.Value {
+		v = reflect.Indirect(v)
+		for idx, fieldIdx := range field.StructField.Index {
+			if fieldIdx >= 0 {
+				v = v.Field(fieldIdx)
+			} else {
+				v = v.Field(-fieldIdx - 1)
 
-					if idx < len(field.StructField.Index)-1 {
-						v = v.Elem()
-					}
+				if v.IsNil() {
+					v.Set(reflect.New(v.Type().Elem()))
+				}
+
+				if idx < len(field.StructField.Index)-1 {
+					v = v.Elem()
 				}
 			}
-			return v
 		}
+		return v
 	}
 
-	fallbackSetter := func(value reflect.Value, v interface{}, setter func(reflect.Value, interface{}) error) (err error) {
+	fallbackSetter := func(ctx context.Context, value reflect.Value, v interface{}, setter func(context.Context, reflect.Value, interface{}) error) (err error) {
 		if v == nil {
-			field.ReflectValueOf(value).Set(reflect.New(field.FieldType).Elem())
+			field.ReflectValueOf(ctx, value).Set(reflect.New(field.FieldType).Elem())
 		} else {
 			reflectV := reflect.ValueOf(v)
 			// Optimal value type acquisition for v
 			reflectValType := reflectV.Type()
 
 			if reflectValType.AssignableTo(field.FieldType) {
-				field.ReflectValueOf(value).Set(reflectV)
+				field.ReflectValueOf(ctx, value).Set(reflectV)
 				return
 			} else if reflectValType.ConvertibleTo(field.FieldType) {
-				field.ReflectValueOf(value).Set(reflectV.Convert(field.FieldType))
+				field.ReflectValueOf(ctx, value).Set(reflectV.Convert(field.FieldType))
 				return
 			} else if field.FieldType.Kind() == reflect.Ptr {
-				fieldValue := field.ReflectValueOf(value)
+				fieldValue := field.ReflectValueOf(ctx, value)
 				fieldType := field.FieldType.Elem()
 
 				if reflectValType.AssignableTo(fieldType) {
@@ -521,13 +567,16 @@ func (field *Field) setupValuerAndSetter() {
 
 			if reflectV.Kind() == reflect.Ptr {
 				if reflectV.IsNil() {
-					field.ReflectValueOf(value).Set(reflect.New(field.FieldType).Elem())
+					field.ReflectValueOf(ctx, value).Set(reflect.New(field.FieldType).Elem())
+				} else if reflectV.Type().Elem().AssignableTo(field.FieldType) {
+					field.ReflectValueOf(ctx, value).Set(reflectV.Elem())
+					return
 				} else {
-					err = setter(value, reflectV.Elem().Interface())
+					err = setter(ctx, value, reflectV.Elem().Interface())
 				}
 			} else if valuer, ok := v.(driver.Valuer); ok {
 				if v, err = valuer.Value(); err == nil {
-					err = setter(value, v)
+					err = setter(ctx, value, v)
 				}
 			} else {
 				return fmt.Errorf("failed to set value %+v to field %s", v, field.Name)
@@ -540,191 +589,201 @@ func (field *Field) setupValuerAndSetter() {
 	// Set
 	switch field.FieldType.Kind() {
 	case reflect.Bool:
-		field.Set = func(value reflect.Value, v interface{}) error {
+		field.Set = func(ctx context.Context, value reflect.Value, v interface{}) error {
 			switch data := v.(type) {
-			case bool:
-				field.ReflectValueOf(value).SetBool(data)
-			case *bool:
-				if data != nil {
-					field.ReflectValueOf(value).SetBool(*data)
-				} else {
-					field.ReflectValueOf(value).SetBool(false)
+			case **bool:
+				if data != nil && *data != nil {
+					field.ReflectValueOf(ctx, value).SetBool(**data)
 				}
+			case bool:
+				field.ReflectValueOf(ctx, value).SetBool(data)
 			case int64:
-				if data > 0 {
-					field.ReflectValueOf(value).SetBool(true)
-				} else {
-					field.ReflectValueOf(value).SetBool(false)
-				}
+				field.ReflectValueOf(ctx, value).SetBool(data > 0)
 			case string:
 				b, _ := strconv.ParseBool(data)
-				field.ReflectValueOf(value).SetBool(b)
+				field.ReflectValueOf(ctx, value).SetBool(b)
 			default:
-				return fallbackSetter(value, v, field.Set)
+				return fallbackSetter(ctx, value, v, field.Set)
 			}
 			return nil
 		}
 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-		field.Set = func(value reflect.Value, v interface{}) (err error) {
+		field.Set = func(ctx context.Context, value reflect.Value, v interface{}) (err error) {
 			switch data := v.(type) {
+			case **int64:
+				if data != nil && *data != nil {
+					field.ReflectValueOf(ctx, value).SetInt(**data)
+				}
 			case int64:
-				field.ReflectValueOf(value).SetInt(data)
+				field.ReflectValueOf(ctx, value).SetInt(data)
 			case int:
-				field.ReflectValueOf(value).SetInt(int64(data))
+				field.ReflectValueOf(ctx, value).SetInt(int64(data))
 			case int8:
-				field.ReflectValueOf(value).SetInt(int64(data))
+				field.ReflectValueOf(ctx, value).SetInt(int64(data))
 			case int16:
-				field.ReflectValueOf(value).SetInt(int64(data))
+				field.ReflectValueOf(ctx, value).SetInt(int64(data))
 			case int32:
-				field.ReflectValueOf(value).SetInt(int64(data))
+				field.ReflectValueOf(ctx, value).SetInt(int64(data))
 			case uint:
-				field.ReflectValueOf(value).SetInt(int64(data))
+				field.ReflectValueOf(ctx, value).SetInt(int64(data))
 			case uint8:
-				field.ReflectValueOf(value).SetInt(int64(data))
+				field.ReflectValueOf(ctx, value).SetInt(int64(data))
 			case uint16:
-				field.ReflectValueOf(value).SetInt(int64(data))
+				field.ReflectValueOf(ctx, value).SetInt(int64(data))
 			case uint32:
-				field.ReflectValueOf(value).SetInt(int64(data))
+				field.ReflectValueOf(ctx, value).SetInt(int64(data))
 			case uint64:
-				field.ReflectValueOf(value).SetInt(int64(data))
+				field.ReflectValueOf(ctx, value).SetInt(int64(data))
 			case float32:
-				field.ReflectValueOf(value).SetInt(int64(data))
+				field.ReflectValueOf(ctx, value).SetInt(int64(data))
 			case float64:
-				field.ReflectValueOf(value).SetInt(int64(data))
+				field.ReflectValueOf(ctx, value).SetInt(int64(data))
 			case []byte:
-				return field.Set(value, string(data))
+				return field.Set(ctx, value, string(data))
 			case string:
 				if i, err := strconv.ParseInt(data, 0, 64); err == nil {
-					field.ReflectValueOf(value).SetInt(i)
+					field.ReflectValueOf(ctx, value).SetInt(i)
 				} else {
 					return err
 				}
 			case time.Time:
 				if field.AutoCreateTime == UnixNanosecond || field.AutoUpdateTime == UnixNanosecond {
-					field.ReflectValueOf(value).SetInt(data.UnixNano())
+					field.ReflectValueOf(ctx, value).SetInt(data.UnixNano())
 				} else if field.AutoCreateTime == UnixMillisecond || field.AutoUpdateTime == UnixMillisecond {
-					field.ReflectValueOf(value).SetInt(data.UnixNano() / 1e6)
+					field.ReflectValueOf(ctx, value).SetInt(data.UnixNano() / 1e6)
 				} else {
-					field.ReflectValueOf(value).SetInt(data.Unix())
+					field.ReflectValueOf(ctx, value).SetInt(data.Unix())
 				}
 			case *time.Time:
 				if data != nil {
 					if field.AutoCreateTime == UnixNanosecond || field.AutoUpdateTime == UnixNanosecond {
-						field.ReflectValueOf(value).SetInt(data.UnixNano())
+						field.ReflectValueOf(ctx, value).SetInt(data.UnixNano())
 					} else if field.AutoCreateTime == UnixMillisecond || field.AutoUpdateTime == UnixMillisecond {
-						field.ReflectValueOf(value).SetInt(data.UnixNano() / 1e6)
+						field.ReflectValueOf(ctx, value).SetInt(data.UnixNano() / 1e6)
 					} else {
-						field.ReflectValueOf(value).SetInt(data.Unix())
+						field.ReflectValueOf(ctx, value).SetInt(data.Unix())
 					}
 				} else {
-					field.ReflectValueOf(value).SetInt(0)
+					field.ReflectValueOf(ctx, value).SetInt(0)
 				}
 			default:
-				return fallbackSetter(value, v, field.Set)
+				return fallbackSetter(ctx, value, v, field.Set)
 			}
 			return err
 		}
 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
-		field.Set = func(value reflect.Value, v interface{}) (err error) {
+		field.Set = func(ctx context.Context, value reflect.Value, v interface{}) (err error) {
 			switch data := v.(type) {
+			case **uint64:
+				if data != nil && *data != nil {
+					field.ReflectValueOf(ctx, value).SetUint(**data)
+				}
 			case uint64:
-				field.ReflectValueOf(value).SetUint(data)
+				field.ReflectValueOf(ctx, value).SetUint(data)
 			case uint:
-				field.ReflectValueOf(value).SetUint(uint64(data))
+				field.ReflectValueOf(ctx, value).SetUint(uint64(data))
 			case uint8:
-				field.ReflectValueOf(value).SetUint(uint64(data))
+				field.ReflectValueOf(ctx, value).SetUint(uint64(data))
 			case uint16:
-				field.ReflectValueOf(value).SetUint(uint64(data))
+				field.ReflectValueOf(ctx, value).SetUint(uint64(data))
 			case uint32:
-				field.ReflectValueOf(value).SetUint(uint64(data))
+				field.ReflectValueOf(ctx, value).SetUint(uint64(data))
 			case int64:
-				field.ReflectValueOf(value).SetUint(uint64(data))
+				field.ReflectValueOf(ctx, value).SetUint(uint64(data))
 			case int:
-				field.ReflectValueOf(value).SetUint(uint64(data))
+				field.ReflectValueOf(ctx, value).SetUint(uint64(data))
 			case int8:
-				field.ReflectValueOf(value).SetUint(uint64(data))
+				field.ReflectValueOf(ctx, value).SetUint(uint64(data))
 			case int16:
-				field.ReflectValueOf(value).SetUint(uint64(data))
+				field.ReflectValueOf(ctx, value).SetUint(uint64(data))
 			case int32:
-				field.ReflectValueOf(value).SetUint(uint64(data))
+				field.ReflectValueOf(ctx, value).SetUint(uint64(data))
 			case float32:
-				field.ReflectValueOf(value).SetUint(uint64(data))
+				field.ReflectValueOf(ctx, value).SetUint(uint64(data))
 			case float64:
-				field.ReflectValueOf(value).SetUint(uint64(data))
+				field.ReflectValueOf(ctx, value).SetUint(uint64(data))
 			case []byte:
-				return field.Set(value, string(data))
+				return field.Set(ctx, value, string(data))
 			case time.Time:
 				if field.AutoCreateTime == UnixNanosecond || field.AutoUpdateTime == UnixNanosecond {
-					field.ReflectValueOf(value).SetUint(uint64(data.UnixNano()))
+					field.ReflectValueOf(ctx, value).SetUint(uint64(data.UnixNano()))
 				} else if field.AutoCreateTime == UnixMillisecond || field.AutoUpdateTime == UnixMillisecond {
-					field.ReflectValueOf(value).SetUint(uint64(data.UnixNano() / 1e6))
+					field.ReflectValueOf(ctx, value).SetUint(uint64(data.UnixNano() / 1e6))
 				} else {
-					field.ReflectValueOf(value).SetUint(uint64(data.Unix()))
+					field.ReflectValueOf(ctx, value).SetUint(uint64(data.Unix()))
 				}
 			case string:
 				if i, err := strconv.ParseUint(data, 0, 64); err == nil {
-					field.ReflectValueOf(value).SetUint(i)
+					field.ReflectValueOf(ctx, value).SetUint(i)
 				} else {
 					return err
 				}
 			default:
-				return fallbackSetter(value, v, field.Set)
+				return fallbackSetter(ctx, value, v, field.Set)
 			}
 			return err
 		}
 	case reflect.Float32, reflect.Float64:
-		field.Set = func(value reflect.Value, v interface{}) (err error) {
+		field.Set = func(ctx context.Context, value reflect.Value, v interface{}) (err error) {
 			switch data := v.(type) {
+			case **float64:
+				if data != nil && *data != nil {
+					field.ReflectValueOf(ctx, value).SetFloat(**data)
+				}
 			case float64:
-				field.ReflectValueOf(value).SetFloat(data)
+				field.ReflectValueOf(ctx, value).SetFloat(data)
 			case float32:
-				field.ReflectValueOf(value).SetFloat(float64(data))
+				field.ReflectValueOf(ctx, value).SetFloat(float64(data))
 			case int64:
-				field.ReflectValueOf(value).SetFloat(float64(data))
+				field.ReflectValueOf(ctx, value).SetFloat(float64(data))
 			case int:
-				field.ReflectValueOf(value).SetFloat(float64(data))
+				field.ReflectValueOf(ctx, value).SetFloat(float64(data))
 			case int8:
-				field.ReflectValueOf(value).SetFloat(float64(data))
+				field.ReflectValueOf(ctx, value).SetFloat(float64(data))
 			case int16:
-				field.ReflectValueOf(value).SetFloat(float64(data))
+				field.ReflectValueOf(ctx, value).SetFloat(float64(data))
 			case int32:
-				field.ReflectValueOf(value).SetFloat(float64(data))
+				field.ReflectValueOf(ctx, value).SetFloat(float64(data))
 			case uint:
-				field.ReflectValueOf(value).SetFloat(float64(data))
+				field.ReflectValueOf(ctx, value).SetFloat(float64(data))
 			case uint8:
-				field.ReflectValueOf(value).SetFloat(float64(data))
+				field.ReflectValueOf(ctx, value).SetFloat(float64(data))
 			case uint16:
-				field.ReflectValueOf(value).SetFloat(float64(data))
+				field.ReflectValueOf(ctx, value).SetFloat(float64(data))
 			case uint32:
-				field.ReflectValueOf(value).SetFloat(float64(data))
+				field.ReflectValueOf(ctx, value).SetFloat(float64(data))
 			case uint64:
-				field.ReflectValueOf(value).SetFloat(float64(data))
+				field.ReflectValueOf(ctx, value).SetFloat(float64(data))
 			case []byte:
-				return field.Set(value, string(data))
+				return field.Set(ctx, value, string(data))
 			case string:
 				if i, err := strconv.ParseFloat(data, 64); err == nil {
-					field.ReflectValueOf(value).SetFloat(i)
+					field.ReflectValueOf(ctx, value).SetFloat(i)
 				} else {
 					return err
 				}
 			default:
-				return fallbackSetter(value, v, field.Set)
+				return fallbackSetter(ctx, value, v, field.Set)
 			}
 			return err
 		}
 	case reflect.String:
-		field.Set = func(value reflect.Value, v interface{}) (err error) {
+		field.Set = func(ctx context.Context, value reflect.Value, v interface{}) (err error) {
 			switch data := v.(type) {
+			case **string:
+				if data != nil && *data != nil {
+					field.ReflectValueOf(ctx, value).SetString(**data)
+				}
 			case string:
-				field.ReflectValueOf(value).SetString(data)
+				field.ReflectValueOf(ctx, value).SetString(data)
 			case []byte:
-				field.ReflectValueOf(value).SetString(string(data))
+				field.ReflectValueOf(ctx, value).SetString(string(data))
 			case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
-				field.ReflectValueOf(value).SetString(utils.ToString(data))
+				field.ReflectValueOf(ctx, value).SetString(utils.ToString(data))
 			case float64, float32:
-				field.ReflectValueOf(value).SetString(fmt.Sprintf("%."+strconv.Itoa(field.Precision)+"f", data))
+				field.ReflectValueOf(ctx, value).SetString(fmt.Sprintf("%."+strconv.Itoa(field.Precision)+"f", data))
 			default:
-				return fallbackSetter(value, v, field.Set)
+				return fallbackSetter(ctx, value, v, field.Set)
 			}
 			return err
 		}
@@ -732,41 +791,49 @@ func (field *Field) setupValuerAndSetter() {
 		fieldValue := reflect.New(field.FieldType)
 		switch fieldValue.Elem().Interface().(type) {
 		case time.Time:
-			field.Set = func(value reflect.Value, v interface{}) error {
+			field.Set = func(ctx context.Context, value reflect.Value, v interface{}) error {
 				switch data := v.(type) {
+				case **time.Time:
+					if data != nil && *data != nil {
+						field.Set(ctx, value, *data)
+					}
 				case time.Time:
-					field.ReflectValueOf(value).Set(reflect.ValueOf(v))
+					field.ReflectValueOf(ctx, value).Set(reflect.ValueOf(v))
 				case *time.Time:
 					if data != nil {
-						field.ReflectValueOf(value).Set(reflect.ValueOf(data).Elem())
+						field.ReflectValueOf(ctx, value).Set(reflect.ValueOf(data).Elem())
 					} else {
-						field.ReflectValueOf(value).Set(reflect.ValueOf(time.Time{}))
+						field.ReflectValueOf(ctx, value).Set(reflect.ValueOf(time.Time{}))
 					}
 				case string:
 					if t, err := now.Parse(data); err == nil {
-						field.ReflectValueOf(value).Set(reflect.ValueOf(t))
+						field.ReflectValueOf(ctx, value).Set(reflect.ValueOf(t))
 					} else {
 						return fmt.Errorf("failed to set string %v to time.Time field %s, failed to parse it as time, got error %v", v, field.Name, err)
 					}
 				default:
-					return fallbackSetter(value, v, field.Set)
+					return fallbackSetter(ctx, value, v, field.Set)
 				}
 				return nil
 			}
 		case *time.Time:
-			field.Set = func(value reflect.Value, v interface{}) error {
+			field.Set = func(ctx context.Context, value reflect.Value, v interface{}) error {
 				switch data := v.(type) {
+				case **time.Time:
+					if data != nil {
+						field.ReflectValueOf(ctx, value).Set(reflect.ValueOf(*data))
+					}
 				case time.Time:
-					fieldValue := field.ReflectValueOf(value)
+					fieldValue := field.ReflectValueOf(ctx, value)
 					if fieldValue.IsNil() {
 						fieldValue.Set(reflect.New(field.FieldType.Elem()))
 					}
 					fieldValue.Elem().Set(reflect.ValueOf(v))
 				case *time.Time:
-					field.ReflectValueOf(value).Set(reflect.ValueOf(v))
+					field.ReflectValueOf(ctx, value).Set(reflect.ValueOf(v))
 				case string:
 					if t, err := now.Parse(data); err == nil {
-						fieldValue := field.ReflectValueOf(value)
+						fieldValue := field.ReflectValueOf(ctx, value)
 						if fieldValue.IsNil() {
 							if v == "" {
 								return nil
@@ -778,27 +845,27 @@ func (field *Field) setupValuerAndSetter() {
 						return fmt.Errorf("failed to set string %v to time.Time field %s, failed to parse it as time, got error %v", v, field.Name, err)
 					}
 				default:
-					return fallbackSetter(value, v, field.Set)
+					return fallbackSetter(ctx, value, v, field.Set)
 				}
 				return nil
 			}
 		default:
 			if _, ok := fieldValue.Elem().Interface().(sql.Scanner); ok {
 				// pointer scanner
-				field.Set = func(value reflect.Value, v interface{}) (err error) {
+				field.Set = func(ctx context.Context, value reflect.Value, v interface{}) (err error) {
 					reflectV := reflect.ValueOf(v)
 					if !reflectV.IsValid() {
-						field.ReflectValueOf(value).Set(reflect.New(field.FieldType).Elem())
+						field.ReflectValueOf(ctx, value).Set(reflect.New(field.FieldType).Elem())
 					} else if reflectV.Type().AssignableTo(field.FieldType) {
-						field.ReflectValueOf(value).Set(reflectV)
+						field.ReflectValueOf(ctx, value).Set(reflectV)
 					} else if reflectV.Kind() == reflect.Ptr {
 						if reflectV.IsNil() || !reflectV.IsValid() {
-							field.ReflectValueOf(value).Set(reflect.New(field.FieldType).Elem())
+							field.ReflectValueOf(ctx, value).Set(reflect.New(field.FieldType).Elem())
 						} else {
-							return field.Set(value, reflectV.Elem().Interface())
+							return field.Set(ctx, value, reflectV.Elem().Interface())
 						}
 					} else {
-						fieldValue := field.ReflectValueOf(value)
+						fieldValue := field.ReflectValueOf(ctx, value)
 						if fieldValue.IsNil() {
 							fieldValue.Set(reflect.New(field.FieldType.Elem()))
 						}
@@ -813,32 +880,61 @@ func (field *Field) setupValuerAndSetter() {
 				}
 			} else if _, ok := fieldValue.Interface().(sql.Scanner); ok {
 				// struct scanner
-				field.Set = func(value reflect.Value, v interface{}) (err error) {
+				field.Set = func(ctx context.Context, value reflect.Value, v interface{}) (err error) {
 					reflectV := reflect.ValueOf(v)
 					if !reflectV.IsValid() {
-						field.ReflectValueOf(value).Set(reflect.New(field.FieldType).Elem())
+						field.ReflectValueOf(ctx, value).Set(reflect.New(field.FieldType).Elem())
 					} else if reflectV.Type().AssignableTo(field.FieldType) {
-						field.ReflectValueOf(value).Set(reflectV)
+						field.ReflectValueOf(ctx, value).Set(reflectV)
 					} else if reflectV.Kind() == reflect.Ptr {
 						if reflectV.IsNil() || !reflectV.IsValid() {
-							field.ReflectValueOf(value).Set(reflect.New(field.FieldType).Elem())
+							field.ReflectValueOf(ctx, value).Set(reflect.New(field.FieldType).Elem())
 						} else {
-							return field.Set(value, reflectV.Elem().Interface())
+							return field.Set(ctx, value, reflectV.Elem().Interface())
 						}
 					} else {
 						if valuer, ok := v.(driver.Valuer); ok {
 							v, _ = valuer.Value()
 						}
 
-						err = field.ReflectValueOf(value).Addr().Interface().(sql.Scanner).Scan(v)
+						err = field.ReflectValueOf(ctx, value).Addr().Interface().(sql.Scanner).Scan(v)
 					}
 					return
 				}
 			} else {
-				field.Set = func(value reflect.Value, v interface{}) (err error) {
-					return fallbackSetter(value, v, field.Set)
+				field.Set = func(ctx context.Context, value reflect.Value, v interface{}) (err error) {
+					return fallbackSetter(ctx, value, v, field.Set)
 				}
 			}
 		}
 	}
+
+	if field.Serializer != nil {
+		var (
+			oldFieldSetter = field.Set
+			sameElemType   bool
+			sameType       = field.FieldType == reflect.ValueOf(field.Serializer).Type()
+		)
+
+		if reflect.ValueOf(field.Serializer).Kind() == reflect.Ptr {
+			sameElemType = field.FieldType == reflect.ValueOf(field.Serializer).Type().Elem()
+		}
+
+		field.Set = func(ctx context.Context, value reflect.Value, v interface{}) (err error) {
+			if s, ok := v.(*serializer); ok {
+				if err = s.Serializer.Scan(ctx, field, value, s.value); err == nil {
+					if sameElemType {
+						field.ReflectValueOf(ctx, value).Set(reflect.ValueOf(s.Serializer).Elem())
+						s.Serializer = reflect.New(reflect.Indirect(reflect.ValueOf(field.Serializer)).Type()).Interface().(SerializerInterface)
+					} else if sameType {
+						field.ReflectValueOf(ctx, value).Set(reflect.ValueOf(s.Serializer))
+						s.Serializer = reflect.New(reflect.Indirect(reflect.ValueOf(field.Serializer)).Type()).Interface().(SerializerInterface)
+					}
+				}
+			} else {
+				err = oldFieldSetter(ctx, value, v)
+			}
+			return
+		}
+	}
 }
diff --git a/schema/interfaces.go b/schema/interfaces.go
index 98abffb..a75a33c 100644
--- a/schema/interfaces.go
+++ b/schema/interfaces.go
@@ -4,22 +4,33 @@ import (
 	"gorm.io/gorm/clause"
 )
 
+// GormDataTypeInterface gorm data type interface
 type GormDataTypeInterface interface {
 	GormDataType() string
 }
 
+// FieldNewValuePool field new scan value pool
+type FieldNewValuePool interface {
+	Get() interface{}
+	Put(interface{})
+}
+
+// CreateClausesInterface create clauses interface
 type CreateClausesInterface interface {
 	CreateClauses(*Field) []clause.Interface
 }
 
+// QueryClausesInterface query clauses interface
 type QueryClausesInterface interface {
 	QueryClauses(*Field) []clause.Interface
 }
 
+// UpdateClausesInterface update clauses interface
 type UpdateClausesInterface interface {
 	UpdateClauses(*Field) []clause.Interface
 }
 
+// DeleteClausesInterface delete clauses interface
 type DeleteClausesInterface interface {
 	DeleteClauses(*Field) []clause.Interface
 }
diff --git a/schema/pool.go b/schema/pool.go
new file mode 100644
index 0000000..f5c7315
--- /dev/null
+++ b/schema/pool.go
@@ -0,0 +1,62 @@
+package schema
+
+import (
+	"reflect"
+	"sync"
+	"time"
+)
+
+// sync pools
+var (
+	normalPool sync.Map
+	stringPool = &sync.Pool{
+		New: func() interface{} {
+			var v string
+			ptrV := &v
+			return &ptrV
+		},
+	}
+	intPool = &sync.Pool{
+		New: func() interface{} {
+			var v int64
+			ptrV := &v
+			return &ptrV
+		},
+	}
+	uintPool = &sync.Pool{
+		New: func() interface{} {
+			var v uint64
+			ptrV := &v
+			return &ptrV
+		},
+	}
+	floatPool = &sync.Pool{
+		New: func() interface{} {
+			var v float64
+			ptrV := &v
+			return &ptrV
+		},
+	}
+	boolPool = &sync.Pool{
+		New: func() interface{} {
+			var v bool
+			ptrV := &v
+			return &ptrV
+		},
+	}
+	timePool = &sync.Pool{
+		New: func() interface{} {
+			var v time.Time
+			ptrV := &v
+			return &ptrV
+		},
+	}
+	poolInitializer = func(reflectType reflect.Type) FieldNewValuePool {
+		v, _ := normalPool.LoadOrStore(reflectType, &sync.Pool{
+			New: func() interface{} {
+				return reflect.New(reflectType).Interface()
+			},
+		})
+		return v.(FieldNewValuePool)
+	}
+)
diff --git a/schema/relationship.go b/schema/relationship.go
index c5d3dca..eae8ab0 100644
--- a/schema/relationship.go
+++ b/schema/relationship.go
@@ -1,6 +1,7 @@
 package schema
 
 import (
+	"context"
 	"fmt"
 	"reflect"
 	"strings"
@@ -576,7 +577,7 @@ func (rel *Relationship) ParseConstraint() *Constraint {
 	return &constraint
 }
 
-func (rel *Relationship) ToQueryConditions(reflectValue reflect.Value) (conds []clause.Expression) {
+func (rel *Relationship) ToQueryConditions(ctx context.Context, reflectValue reflect.Value) (conds []clause.Expression) {
 	table := rel.FieldSchema.Table
 	foreignFields := []*Field{}
 	relForeignKeys := []string{}
@@ -616,7 +617,7 @@ func (rel *Relationship) ToQueryConditions(reflectValue reflect.Value) (conds []
 		}
 	}
 
-	_, foreignValues := GetIdentityFieldValuesMap(reflectValue, foreignFields)
+	_, foreignValues := GetIdentityFieldValuesMap(ctx, reflectValue, foreignFields)
 	column, values := ToQueryValues(table, relForeignKeys, foreignValues)
 
 	conds = append(conds, clause.IN{Column: column, Values: values})
diff --git a/schema/serializer.go b/schema/serializer.go
new file mode 100644
index 0000000..6859753
--- /dev/null
+++ b/schema/serializer.go
@@ -0,0 +1,125 @@
+package schema
+
+import (
+	"context"
+	"database/sql"
+	"database/sql/driver"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"reflect"
+	"strings"
+	"sync"
+	"time"
+)
+
+var serializerMap = sync.Map{}
+
+// RegisterSerializer register serializer
+func RegisterSerializer(name string, serializer SerializerInterface) {
+	serializerMap.Store(strings.ToLower(name), serializer)
+}
+
+// GetSerializer get serializer
+func GetSerializer(name string) (serializer SerializerInterface, ok bool) {
+	v, ok := serializerMap.Load(strings.ToLower(name))
+	if ok {
+		serializer, ok = v.(SerializerInterface)
+	}
+	return serializer, ok
+}
+
+func init() {
+	RegisterSerializer("json", JSONSerializer{})
+	RegisterSerializer("unixtime", UnixSecondSerializer{})
+}
+
+// Serializer field value serializer
+type serializer struct {
+	Field           *Field
+	Serializer      SerializerInterface
+	SerializeValuer SerializerValuerInterface
+	Destination     reflect.Value
+	Context         context.Context
+	value           interface{}
+	fieldValue      interface{}
+}
+
+// Scan implements sql.Scanner interface
+func (s *serializer) Scan(value interface{}) error {
+	s.value = value
+	return nil
+}
+
+// Value implements driver.Valuer interface
+func (s serializer) Value() (driver.Value, error) {
+	return s.SerializeValuer.Value(s.Context, s.Field, s.Destination, s.fieldValue)
+}
+
+// SerializerInterface serializer interface
+type SerializerInterface interface {
+	Scan(ctx context.Context, field *Field, dst reflect.Value, dbValue interface{}) error
+	SerializerValuerInterface
+}
+
+// SerializerValuerInterface serializer valuer interface
+type SerializerValuerInterface interface {
+	Value(ctx context.Context, field *Field, dst reflect.Value, fieldValue interface{}) (interface{}, error)
+}
+
+// JSONSerializer json serializer
+type JSONSerializer struct {
+}
+
+// Scan implements serializer interface
+func (JSONSerializer) Scan(ctx context.Context, field *Field, dst reflect.Value, dbValue interface{}) (err error) {
+	fieldValue := reflect.New(field.FieldType)
+
+	if dbValue != nil {
+		var bytes []byte
+		switch v := dbValue.(type) {
+		case []byte:
+			bytes = v
+		case string:
+			bytes = []byte(v)
+		default:
+			return errors.New(fmt.Sprint("Failed to unmarshal JSONB value:", dbValue))
+		}
+
+		err = json.Unmarshal(bytes, fieldValue.Interface())
+	}
+
+	field.ReflectValueOf(ctx, dst).Set(fieldValue.Elem())
+	return
+}
+
+// Value implements serializer interface
+func (JSONSerializer) Value(ctx context.Context, field *Field, dst reflect.Value, fieldValue interface{}) (interface{}, error) {
+	result, err := json.Marshal(fieldValue)
+	return string(result), err
+}
+
+// UnixSecondSerializer json serializer
+type UnixSecondSerializer struct {
+}
+
+// Scan implements serializer interface
+func (UnixSecondSerializer) Scan(ctx context.Context, field *Field, dst reflect.Value, dbValue interface{}) (err error) {
+	t := sql.NullTime{}
+	if err = t.Scan(dbValue); err == nil {
+		err = field.Set(ctx, dst, t.Time)
+	}
+
+	return
+}
+
+// Value implements serializer interface
+func (UnixSecondSerializer) Value(ctx context.Context, field *Field, dst reflect.Value, fieldValue interface{}) (result interface{}, err error) {
+	switch v := fieldValue.(type) {
+	case int64, int, uint, uint64, int32, uint32, int16, uint16:
+		result = time.Unix(reflect.ValueOf(v).Int(), 0)
+	default:
+		err = fmt.Errorf("invalid field type %#v for UnixSecondSerializer, only int, uint supported", v)
+	}
+	return
+}
diff --git a/schema/utils.go b/schema/utils.go
index e005cc7..2720c53 100644
--- a/schema/utils.go
+++ b/schema/utils.go
@@ -1,6 +1,7 @@
 package schema
 
 import (
+	"context"
 	"reflect"
 	"regexp"
 	"strings"
@@ -59,13 +60,13 @@ func removeSettingFromTag(tag reflect.StructTag, names ...string) reflect.Struct
 }
 
 // GetRelationsValues get relations's values from a reflect value
-func GetRelationsValues(reflectValue reflect.Value, rels []*Relationship) (reflectResults reflect.Value) {
+func GetRelationsValues(ctx context.Context, reflectValue reflect.Value, rels []*Relationship) (reflectResults reflect.Value) {
 	for _, rel := range rels {
 		reflectResults = reflect.MakeSlice(reflect.SliceOf(reflect.PtrTo(rel.FieldSchema.ModelType)), 0, 1)
 
 		appendToResults := func(value reflect.Value) {
-			if _, isZero := rel.Field.ValueOf(value); !isZero {
-				result := reflect.Indirect(rel.Field.ReflectValueOf(value))
+			if _, isZero := rel.Field.ValueOf(ctx, value); !isZero {
+				result := reflect.Indirect(rel.Field.ReflectValueOf(ctx, value))
 				switch result.Kind() {
 				case reflect.Struct:
 					reflectResults = reflect.Append(reflectResults, result.Addr())
@@ -97,7 +98,7 @@ func GetRelationsValues(reflectValue reflect.Value, rels []*Relationship) (refle
 }
 
 // GetIdentityFieldValuesMap get identity map from fields
-func GetIdentityFieldValuesMap(reflectValue reflect.Value, fields []*Field) (map[string][]reflect.Value, [][]interface{}) {
+func GetIdentityFieldValuesMap(ctx context.Context, reflectValue reflect.Value, fields []*Field) (map[string][]reflect.Value, [][]interface{}) {
 	var (
 		results       = [][]interface{}{}
 		dataResults   = map[string][]reflect.Value{}
@@ -110,7 +111,7 @@ func GetIdentityFieldValuesMap(reflectValue reflect.Value, fields []*Field) (map
 		results = [][]interface{}{make([]interface{}, len(fields))}
 
 		for idx, field := range fields {
-			results[0][idx], zero = field.ValueOf(reflectValue)
+			results[0][idx], zero = field.ValueOf(ctx, reflectValue)
 			notZero = notZero || !zero
 		}
 
@@ -135,7 +136,7 @@ func GetIdentityFieldValuesMap(reflectValue reflect.Value, fields []*Field) (map
 			fieldValues := make([]interface{}, len(fields))
 			notZero = false
 			for idx, field := range fields {
-				fieldValues[idx], zero = field.ValueOf(elem)
+				fieldValues[idx], zero = field.ValueOf(ctx, elem)
 				notZero = notZero || !zero
 			}
 
@@ -155,12 +156,12 @@ func GetIdentityFieldValuesMap(reflectValue reflect.Value, fields []*Field) (map
 }
 
 // GetIdentityFieldValuesMapFromValues get identity map from fields
-func GetIdentityFieldValuesMapFromValues(values []interface{}, fields []*Field) (map[string][]reflect.Value, [][]interface{}) {
+func GetIdentityFieldValuesMapFromValues(ctx context.Context, 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)
+		rm, rs := GetIdentityFieldValuesMap(ctx, reflect.Indirect(reflect.ValueOf(v)), fields)
 		for k, v := range rm {
 			resultsMap[k] = append(resultsMap[k], v...)
 		}
diff --git a/soft_delete.go b/soft_delete.go
index 4582161..ba6d211 100644
--- a/soft_delete.go
+++ b/soft_delete.go
@@ -135,7 +135,7 @@ func (sd SoftDeleteDeleteClause) ModifyStatement(stmt *Statement) {
 		stmt.SetColumn(sd.Field.DBName, curTime, true)
 
 		if stmt.Schema != nil {
-			_, queryValues := schema.GetIdentityFieldValuesMap(stmt.ReflectValue, stmt.Schema.PrimaryFields)
+			_, queryValues := schema.GetIdentityFieldValuesMap(stmt.Context, stmt.ReflectValue, stmt.Schema.PrimaryFields)
 			column, values := schema.ToQueryValues(stmt.Table, stmt.Schema.PrimaryFieldDBNames, queryValues)
 
 			if len(values) > 0 {
@@ -143,7 +143,7 @@ func (sd SoftDeleteDeleteClause) ModifyStatement(stmt *Statement) {
 			}
 
 			if stmt.ReflectValue.CanAddr() && stmt.Dest != stmt.Model && stmt.Model != nil {
-				_, queryValues = schema.GetIdentityFieldValuesMap(reflect.ValueOf(stmt.Model), stmt.Schema.PrimaryFields)
+				_, queryValues = schema.GetIdentityFieldValuesMap(stmt.Context, reflect.ValueOf(stmt.Model), stmt.Schema.PrimaryFields)
 				column, values = schema.ToQueryValues(stmt.Table, stmt.Schema.PrimaryFieldDBNames, queryValues)
 
 				if len(values) > 0 {
diff --git a/statement.go b/statement.go
index 2321264..cb47177 100644
--- a/statement.go
+++ b/statement.go
@@ -389,7 +389,7 @@ func (stmt *Statement) BuildCondition(query interface{}, args ...interface{}) []
 					for _, field := range s.Fields {
 						selected := selectedColumns[field.DBName] || selectedColumns[field.Name]
 						if selected || (!restricted && field.Readable) {
-							if v, isZero := field.ValueOf(reflectValue); !isZero || selected {
+							if v, isZero := field.ValueOf(stmt.Context, reflectValue); !isZero || selected {
 								if field.DBName != "" {
 									conds = append(conds, clause.Eq{Column: clause.Column{Table: clause.CurrentTable, Name: field.DBName}, Value: v})
 								} else if field.DataType != "" {
@@ -403,7 +403,7 @@ func (stmt *Statement) BuildCondition(query interface{}, args ...interface{}) []
 						for _, field := range s.Fields {
 							selected := selectedColumns[field.DBName] || selectedColumns[field.Name]
 							if selected || (!restricted && field.Readable) {
-								if v, isZero := field.ValueOf(reflectValue.Index(i)); !isZero || selected {
+								if v, isZero := field.ValueOf(stmt.Context, reflectValue.Index(i)); !isZero || selected {
 									if field.DBName != "" {
 										conds = append(conds, clause.Eq{Column: clause.Column{Table: clause.CurrentTable, Name: field.DBName}, Value: v})
 									} else if field.DataType != "" {
@@ -562,7 +562,7 @@ func (stmt *Statement) SetColumn(name string, value interface{}, fromCallbacks .
 
 				switch destValue.Kind() {
 				case reflect.Struct:
-					field.Set(destValue, value)
+					field.Set(stmt.Context, destValue, value)
 				default:
 					stmt.AddError(ErrInvalidData)
 				}
@@ -572,10 +572,10 @@ func (stmt *Statement) SetColumn(name string, value interface{}, fromCallbacks .
 			case reflect.Slice, reflect.Array:
 				if len(fromCallbacks) > 0 {
 					for i := 0; i < stmt.ReflectValue.Len(); i++ {
-						field.Set(stmt.ReflectValue.Index(i), value)
+						field.Set(stmt.Context, stmt.ReflectValue.Index(i), value)
 					}
 				} else {
-					field.Set(stmt.ReflectValue.Index(stmt.CurDestIndex), value)
+					field.Set(stmt.Context, stmt.ReflectValue.Index(stmt.CurDestIndex), value)
 				}
 			case reflect.Struct:
 				if !stmt.ReflectValue.CanAddr() {
@@ -583,7 +583,7 @@ func (stmt *Statement) SetColumn(name string, value interface{}, fromCallbacks .
 					return
 				}
 
-				field.Set(stmt.ReflectValue, value)
+				field.Set(stmt.Context, stmt.ReflectValue, value)
 			}
 		} else {
 			stmt.AddError(ErrInvalidField)
@@ -603,7 +603,7 @@ func (stmt *Statement) Changed(fields ...string) bool {
 
 	selectColumns, restricted := stmt.SelectAndOmitColumns(false, true)
 	changed := func(field *schema.Field) bool {
-		fieldValue, _ := field.ValueOf(modelValue)
+		fieldValue, _ := field.ValueOf(stmt.Context, modelValue)
 		if v, ok := selectColumns[field.DBName]; (ok && v) || (!ok && !restricted) {
 			if v, ok := stmt.Dest.(map[string]interface{}); ok {
 				if fv, ok := v[field.Name]; ok {
@@ -617,7 +617,7 @@ func (stmt *Statement) Changed(fields ...string) bool {
 					destValue = destValue.Elem()
 				}
 
-				changedValue, zero := field.ValueOf(destValue)
+				changedValue, zero := field.ValueOf(stmt.Context, destValue)
 				return !zero && !utils.AssertEqual(changedValue, fieldValue)
 			}
 		}
diff --git a/utils/utils.go b/utils/utils.go
index f00f92b..28ca0da 100644
--- a/utils/utils.go
+++ b/utils/utils.go
@@ -36,17 +36,14 @@ func IsValidDBNameChar(c rune) bool {
 	return !unicode.IsLetter(c) && !unicode.IsNumber(c) && c != '.' && c != '*' && c != '_' && c != '$' && c != '@'
 }
 
-func CheckTruth(val interface{}) bool {
-	if v, ok := val.(bool); ok {
-		return v
-	}
-
-	if v, ok := val.(string); ok {
-		v = strings.ToLower(v)
-		return v != "false"
+// CheckTruth check string true or not
+func CheckTruth(vals ...string) bool {
+	for _, val := range vals {
+		if !strings.EqualFold(val, "false") && val != "" {
+			return true
+		}
 	}
-
-	return !reflect.ValueOf(val).IsZero()
+	return false
 }
 
 func ToStringKey(values ...interface{}) string {


Test patch:
diff --git a/schema/field_test.go b/schema/field_test.go
index 8fa46b8..300e375 100644
--- a/schema/field_test.go
+++ b/schema/field_test.go
@@ -1,6 +1,7 @@
 package schema_test
 
 import (
+	"context"
 	"database/sql"
 	"reflect"
 	"sync"
@@ -57,7 +58,7 @@ func TestFieldValuerAndSetter(t *testing.T) {
 	}
 
 	for k, v := range newValues {
-		if err := userSchema.FieldsByDBName[k].Set(reflectValue, v); err != nil {
+		if err := userSchema.FieldsByDBName[k].Set(context.Background(), reflectValue, v); err != nil {
 			t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
 		}
 	}
@@ -80,7 +81,7 @@ func TestFieldValuerAndSetter(t *testing.T) {
 	}
 
 	for k, v := range newValues2 {
-		if err := userSchema.FieldsByDBName[k].Set(reflectValue, v); err != nil {
+		if err := userSchema.FieldsByDBName[k].Set(context.Background(), reflectValue, v); err != nil {
 			t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
 		}
 	}
@@ -132,7 +133,7 @@ func TestPointerFieldValuerAndSetter(t *testing.T) {
 	}
 
 	for k, v := range newValues {
-		if err := userSchema.FieldsByDBName[k].Set(reflectValue, v); err != nil {
+		if err := userSchema.FieldsByDBName[k].Set(context.Background(), reflectValue, v); err != nil {
 			t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
 		}
 	}
@@ -151,7 +152,7 @@ func TestPointerFieldValuerAndSetter(t *testing.T) {
 	}
 
 	for k, v := range newValues2 {
-		if err := userSchema.FieldsByDBName[k].Set(reflectValue, v); err != nil {
+		if err := userSchema.FieldsByDBName[k].Set(context.Background(), reflectValue, v); err != nil {
 			t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
 		}
 	}
@@ -202,7 +203,7 @@ func TestAdvancedDataTypeValuerAndSetter(t *testing.T) {
 	}
 
 	for k, v := range newValues {
-		if err := userSchema.FieldsByDBName[k].Set(reflectValue, v); err != nil {
+		if err := userSchema.FieldsByDBName[k].Set(context.Background(), reflectValue, v); err != nil {
 			t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
 		}
 	}
@@ -219,7 +220,7 @@ func TestAdvancedDataTypeValuerAndSetter(t *testing.T) {
 	}
 
 	for k, v := range newValues2 {
-		if err := userSchema.FieldsByDBName[k].Set(reflectValue, v); err != nil {
+		if err := userSchema.FieldsByDBName[k].Set(context.Background(), reflectValue, v); err != nil {
 			t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
 		}
 	}
diff --git a/schema/schema_helper_test.go b/schema/schema_helper_test.go
index 6d2bc66..9abaecb 100644
--- a/schema/schema_helper_test.go
+++ b/schema/schema_helper_test.go
@@ -1,6 +1,7 @@
 package schema_test
 
 import (
+	"context"
 	"fmt"
 	"reflect"
 	"strings"
@@ -203,7 +204,7 @@ func checkSchemaRelation(t *testing.T, s *schema.Schema, relation Relation) {
 func checkField(t *testing.T, s *schema.Schema, value reflect.Value, values map[string]interface{}) {
 	for k, v := range values {
 		t.Run("CheckField/"+k, func(t *testing.T) {
-			fv, _ := s.FieldsByDBName[k].ValueOf(value)
+			fv, _ := s.FieldsByDBName[k].ValueOf(context.Background(), value)
 			tests.AssertEqual(t, v, fv)
 		})
 	}
diff --git a/tests/create_test.go b/tests/create_test.go
index af2abdb..2b23d44 100644
--- a/tests/create_test.go
+++ b/tests/create_test.go
@@ -123,7 +123,7 @@ func TestCreateFromMap(t *testing.T) {
 		{"name": "create_from_map_3", "Age": 20},
 	}
 
-	if err := DB.Model(&User{}).Create(datas).Error; err != nil {
+	if err := DB.Model(&User{}).Create(&datas).Error; err != nil {
 		t.Fatalf("failed to create data from slice of map, got error: %v", err)
 	}
 
diff --git a/tests/go.mod b/tests/go.mod
index 3453f77..0cd0363 100644
--- a/tests/go.mod
+++ b/tests/go.mod
@@ -3,17 +3,16 @@ module gorm.io/gorm/tests
 go 1.14
 
 require (
-	github.com/denisenkom/go-mssqldb v0.12.0 // indirect
 	github.com/google/uuid v1.3.0
 	github.com/jackc/pgx/v4 v4.15.0 // indirect
 	github.com/jinzhu/now v1.1.4
 	github.com/lib/pq v1.10.4
 	github.com/mattn/go-sqlite3 v1.14.11 // indirect
-	golang.org/x/crypto v0.0.0-20220208233918-bba287dce954 // indirect
-	gorm.io/driver/mysql v1.2.3
-	gorm.io/driver/postgres v1.2.3
-	gorm.io/driver/sqlite v1.2.6
-	gorm.io/driver/sqlserver v1.2.1
+	golang.org/x/crypto v0.0.0-20220214200702-86341886e292 // indirect
+	gorm.io/driver/mysql v1.3.0
+	gorm.io/driver/postgres v1.3.0
+	gorm.io/driver/sqlite v1.3.0
+	gorm.io/driver/sqlserver v1.3.0
 	gorm.io/gorm v1.22.5
 )
 
diff --git a/tests/migrate_test.go b/tests/migrate_test.go
index aa0a84a..5e9c01f 100644
--- a/tests/migrate_test.go
+++ b/tests/migrate_test.go
@@ -92,7 +92,7 @@ func TestAutoMigrateSelfReferential(t *testing.T) {
 }
 
 func TestSmartMigrateColumn(t *testing.T) {
-	fullSupported := map[string]bool{"mysql": true}[DB.Dialector.Name()]
+	fullSupported := map[string]bool{"mysql": true, "postgres": true}[DB.Dialector.Name()]
 
 	type UserMigrateColumn struct {
 		ID       uint
@@ -313,9 +313,15 @@ func TestMigrateIndexes(t *testing.T) {
 }
 
 func TestMigrateColumns(t *testing.T) {
+	fullSupported := map[string]bool{"sqlite": true, "mysql": true, "postgres": true, "sqlserver": true}[DB.Dialector.Name()]
+	sqlite := DB.Dialector.Name() == "sqlite"
+	sqlserver := DB.Dialector.Name() == "sqlserver"
+
 	type ColumnStruct struct {
 		gorm.Model
 		Name string
+		Age  int    `gorm:"default:18;comment:my age"`
+		Code string `gorm:"unique"`
 	}
 
 	DB.Migrator().DropTable(&ColumnStruct{})
@@ -340,10 +346,29 @@ func TestMigrateColumns(t *testing.T) {
 		stmt.Parse(&ColumnStruct2{})
 
 		for _, columnType := range columnTypes {
-			if columnType.Name() == "name" {
+			switch columnType.Name() {
+			case "id":
+				if v, ok := columnType.PrimaryKey(); (fullSupported || ok) && !v {
+					t.Fatalf("column id primary key should be correct, name: %v, column: %#v", columnType.Name(), columnType)
+				}
+			case "name":
 				dataType := DB.Dialector.DataTypeOf(stmt.Schema.LookUpField(columnType.Name()))
 				if !strings.Contains(strings.ToUpper(dataType), strings.ToUpper(columnType.DatabaseTypeName())) {
-					t.Errorf("column type should be correct, name: %v, length: %v, expects: %v", columnType.Name(), columnType.DatabaseTypeName(), dataType)
+					t.Fatalf("column name type should be correct, name: %v, length: %v, expects: %v, column: %#v", columnType.Name(), columnType.DatabaseTypeName(), dataType, columnType)
+				}
+				if length, ok := columnType.Length(); ((fullSupported && !sqlite) || ok) && length != 100 {
+					t.Fatalf("column name length should be correct, name: %v, length: %v, expects: %v, column: %#v", columnType.Name(), length, 100, columnType)
+				}
+			case "age":
+				if v, ok := columnType.DefaultValue(); (fullSupported || ok) && v != "18" {
+					t.Fatalf("column age default value should be correct, name: %v, column: %#v", columnType.Name(), columnType)
+				}
+				if v, ok := columnType.Comment(); ((fullSupported && !sqlite && !sqlserver) || ok) && v != "my age" {
+					t.Fatalf("column age comment should be correct, name: %v, column: %#v", columnType.Name(), columnType)
+				}
+			case "code":
+				if v, ok := columnType.Unique(); (fullSupported || ok) && !v {
+					t.Fatalf("column code unique should be correct, name: %v, column: %#v", columnType.Name(), columnType)
 				}
 			}
 		}
diff --git a/tests/serializer_test.go b/tests/serializer_test.go
new file mode 100644
index 0000000..3ed733d
--- /dev/null
+++ b/tests/serializer_test.go
@@ -0,0 +1,71 @@
+package tests_test
+
+import (
+	"bytes"
+	"context"
+	"fmt"
+	"reflect"
+	"strings"
+	"testing"
+	"time"
+
+	"gorm.io/gorm"
+	"gorm.io/gorm/schema"
+	. "gorm.io/gorm/utils/tests"
+)
+
+type SerializerStruct struct {
+	gorm.Model
+	Name            []byte                 `gorm:"json"`
+	Roles           Roles                  `gorm:"serializer:json"`
+	Contracts       map[string]interface{} `gorm:"serializer:json"`
+	CreatedTime     int64                  `gorm:"serializer:unixtime;type:time"` // store time in db, use int as field type
+	EncryptedString EncryptedString
+}
+
+type Roles []string
+type EncryptedString string
+
+func (es *EncryptedString) Scan(ctx context.Context, field *schema.Field, dst reflect.Value, dbValue interface{}) (err error) {
+	switch value := dbValue.(type) {
+	case []byte:
+		*es = EncryptedString(bytes.TrimPrefix(value, []byte("hello")))
+	case string:
+		*es = EncryptedString(strings.TrimPrefix(value, "hello"))
+	default:
+		return fmt.Errorf("unsupported data %v", dbValue)
+	}
+	return nil
+}
+
+func (es EncryptedString) Value(ctx context.Context, field *schema.Field, dst reflect.Value, fieldValue interface{}) (interface{}, error) {
+	return "hello" + string(es), nil
+}
+
+func TestSerializer(t *testing.T) {
+	DB.Migrator().DropTable(&SerializerStruct{})
+	if err := DB.Migrator().AutoMigrate(&SerializerStruct{}); err != nil {
+		t.Fatalf("no error should happen when migrate scanner, valuer struct, got error %v", err)
+	}
+
+	createdAt := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
+
+	data := SerializerStruct{
+		Name:            []byte("jinzhu"),
+		Roles:           []string{"r1", "r2"},
+		Contracts:       map[string]interface{}{"name": "jinzhu", "age": 10},
+		EncryptedString: EncryptedString("pass"),
+		CreatedTime:     createdAt.Unix(),
+	}
+
+	if err := DB.Create(&data).Error; err != nil {
+		t.Fatalf("failed to create data, got error %v", err)
+	}
+
+	var result SerializerStruct
+	if err := DB.First(&result, data.ID).Error; err != nil {
+		t.Fatalf("failed to query data, got error %v", err)
+	}
+
+	AssertEqual(t, result, data)
+}