Repository: go-gorm/gorm
Pull request #5012 (2022-01-20 17:12:10)

Inherit clone flag (NewDB) on transaction creation
- [X] Do only one thing
- [X] Non breaking API changes
- [X] Tested

### What did this pull request do?

I find it very reassuring to know that after a finisher API, I get a clean db object for my next queries.
If you look at the example in https://gorm.io/docs you'd see many queries running one after the other.. but in reality they wouldn’t work in transaction.
That’s because in default mode, NewDB is false and will make all the clauses stay even after a finisher API.

My solution is just to have the value of the clone flag in the “parent” db object, be injected to its children transactions.


### User Case Description

I have many usages of transactions around my code and many of them consist of multiple queries that aren't sharing the same clauses (e.g different `WHERE`).
So instead of having to use `db.begin().Session(gorm.Session{NewDB: true})` on each transaction, because :
A. it is verbose
B. It hurts maintainability, since new devs are expecting of all transaction to work as their parent DB object.



Patch:
diff --git a/.github/workflows/invalid_question.yml b/.github/workflows/invalid_question.yml
index dfd2ddd..868bcc3 100644
--- a/.github/workflows/invalid_question.yml
+++ b/.github/workflows/invalid_question.yml
@@ -13,10 +13,10 @@ jobs:
       uses: actions/stale@v4
       with:
         repo-token: ${{ secrets.GITHUB_TOKEN }}
-        stale-issue-message: "This issue has been marked as invalid question, please give more information by following the `Question` template, if you believe there is a bug of GORM, please create a pull request that could reproduce the issue on [https://github.com/go-gorm/playground](https://github.com/go-gorm/playground), the issue will be closed in 2 days if no further activity occurs. most likely your question already answered https://github.com/go-gorm/gorm/issues or described in the document https://gorm.io ✨ [Search Before Asking](https://stackoverflow.com/help/how-to-ask) ✨"
+        stale-issue-message: "This issue has been marked as invalid question, please give more information by following the `Question` template, if you believe there is a bug of GORM, please create a pull request that could reproduce the issue on [https://github.com/go-gorm/playground](https://github.com/go-gorm/playground), the issue will be closed in 30 days if no further activity occurs. most likely your question already answered https://github.com/go-gorm/gorm/issues or described in the document https://gorm.io ✨ [Search Before Asking](https://stackoverflow.com/help/how-to-ask) ✨"
         stale-issue-label: "status:stale"
         days-before-stale: 0
-        days-before-close: 2
+        days-before-close: 30
         remove-stale-when-updated: true
         only-labels: "type:invalid question"
 
diff --git a/.github/workflows/missing_playground.yml b/.github/workflows/missing_playground.yml
index cdb097d..3efc90f 100644
--- a/.github/workflows/missing_playground.yml
+++ b/.github/workflows/missing_playground.yml
@@ -13,9 +13,9 @@ jobs:
       uses: actions/stale@v4
       with:
         repo-token: ${{ secrets.GITHUB_TOKEN }}
-        stale-issue-message: "The issue has been automatically marked as stale as it missing playground pull request link, which is important to help others understand your issue effectively and make sure the issue hasn't been fixed on latest master, checkout [https://github.com/go-gorm/playground](https://github.com/go-gorm/playground) for details. it will be closed in 2 days if no further activity occurs. if you are asking question, please use the `Question` template, most likely your question already answered https://github.com/go-gorm/gorm/issues or described in the document https://gorm.io ✨ [Search Before Asking](https://stackoverflow.com/help/how-to-ask) ✨"
+        stale-issue-message: "The issue has been automatically marked as stale as it missing playground pull request link, which is important to help others understand your issue effectively and make sure the issue hasn't been fixed on latest master, checkout [https://github.com/go-gorm/playground](https://github.com/go-gorm/playground) for details. it will be closed in 30 days if no further activity occurs. if you are asking question, please use the `Question` template, most likely your question already answered https://github.com/go-gorm/gorm/issues or described in the document https://gorm.io ✨ [Search Before Asking](https://stackoverflow.com/help/how-to-ask) ✨"
         stale-issue-label: "status:stale"
         days-before-stale: 0
-        days-before-close: 2
+        days-before-close: 30
         remove-stale-when-updated: true
         only-labels: "type:missing reproduction steps"
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
index d541929..e0be186 100644
--- a/.github/workflows/stale.yml
+++ b/.github/workflows/stale.yml
@@ -13,9 +13,9 @@ jobs:
       uses: actions/stale@v4
       with:
         repo-token: ${{ secrets.GITHUB_TOKEN }}
-        stale-issue-message: "This issue has been automatically marked as stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 30 days"
-        days-before-stale: 60
-        days-before-close: 30
+        stale-issue-message: "This issue has been automatically marked as stale because it has been open 360 days with no activity. Remove stale label or comment or this will be closed in 180 days"
+        days-before-stale: 360
+        days-before-close: 180
         stale-issue-label: "status:stale"
         exempt-issue-labels: 'type:feature,type:with reproduction steps,type:has pull request'
         stale-pr-label: 'status:stale'
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 c2bbf5f..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})
 				}
 			}
@@ -100,7 +100,7 @@ func BuildQuerySQL(db *gorm.DB) {
 		}
 
 		if len(db.Statement.Joins) != 0 || len(joins) != 0 {
-			if len(db.Statement.Selects) == 0 && db.Statement.Schema != nil {
+			if len(db.Statement.Selects) == 0 && len(db.Statement.Omits) == 0 && db.Statement.Schema != nil {
 				clauseSelect.Columns = make([]clause.Column, len(db.Statement.Schema.DBNames))
 				for idx, dbName := range db.Statement.Schema.DBNames {
 					clauseSelect.Columns[idx] = clause.Column{Table: db.Statement.Table, Name: dbName}
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/clause/where.go b/clause/where.go
index 20a0113..10b6df8 100644
--- a/clause/where.go
+++ b/clause/where.go
@@ -4,6 +4,11 @@ import (
 	"strings"
 )
 
+const (
+	AndWithSpace = " AND "
+	OrWithSpace  = " OR "
+)
+
 // Where where clause
 type Where struct {
 	Exprs []Expression
@@ -26,7 +31,7 @@ func (where Where) Build(builder Builder) {
 		}
 	}
 
-	buildExprs(where.Exprs, builder, " AND ")
+	buildExprs(where.Exprs, builder, AndWithSpace)
 }
 
 func buildExprs(exprs []Expression, builder Builder, joinCond string) {
@@ -35,7 +40,7 @@ func buildExprs(exprs []Expression, builder Builder, joinCond string) {
 	for idx, expr := range exprs {
 		if idx > 0 {
 			if v, ok := expr.(OrConditions); ok && len(v.Exprs) == 1 {
-				builder.WriteString(" OR ")
+				builder.WriteString(OrWithSpace)
 			} else {
 				builder.WriteString(joinCond)
 			}
@@ -46,23 +51,23 @@ func buildExprs(exprs []Expression, builder Builder, joinCond string) {
 			case OrConditions:
 				if len(v.Exprs) == 1 {
 					if e, ok := v.Exprs[0].(Expr); ok {
-						sql := strings.ToLower(e.SQL)
-						wrapInParentheses = strings.Contains(sql, "and") || strings.Contains(sql, "or")
+						sql := strings.ToUpper(e.SQL)
+						wrapInParentheses = strings.Contains(sql, AndWithSpace) || strings.Contains(sql, OrWithSpace)
 					}
 				}
 			case AndConditions:
 				if len(v.Exprs) == 1 {
 					if e, ok := v.Exprs[0].(Expr); ok {
-						sql := strings.ToLower(e.SQL)
-						wrapInParentheses = strings.Contains(sql, "and") || strings.Contains(sql, "or")
+						sql := strings.ToUpper(e.SQL)
+						wrapInParentheses = strings.Contains(sql, AndWithSpace) || strings.Contains(sql, OrWithSpace)
 					}
 				}
 			case Expr:
-				sql := strings.ToLower(v.SQL)
-				wrapInParentheses = strings.Contains(sql, "and") || strings.Contains(sql, "or")
+				sql := strings.ToUpper(v.SQL)
+				wrapInParentheses = strings.Contains(sql, AndWithSpace) || strings.Contains(sql, OrWithSpace)
 			case NamedExpr:
-				sql := strings.ToLower(v.SQL)
-				wrapInParentheses = strings.Contains(sql, "and") || strings.Contains(sql, "or")
+				sql := strings.ToUpper(v.SQL)
+				wrapInParentheses = strings.Contains(sql, AndWithSpace) || strings.Contains(sql, OrWithSpace)
 			}
 		}
 
@@ -110,10 +115,10 @@ type AndConditions struct {
 func (and AndConditions) Build(builder Builder) {
 	if len(and.Exprs) > 1 {
 		builder.WriteByte('(')
-		buildExprs(and.Exprs, builder, " AND ")
+		buildExprs(and.Exprs, builder, AndWithSpace)
 		builder.WriteByte(')')
 	} else {
-		buildExprs(and.Exprs, builder, " AND ")
+		buildExprs(and.Exprs, builder, AndWithSpace)
 	}
 }
 
@@ -131,10 +136,10 @@ type OrConditions struct {
 func (or OrConditions) Build(builder Builder) {
 	if len(or.Exprs) > 1 {
 		builder.WriteByte('(')
-		buildExprs(or.Exprs, builder, " OR ")
+		buildExprs(or.Exprs, builder, OrWithSpace)
 		builder.WriteByte(')')
 	} else {
-		buildExprs(or.Exprs, builder, " OR ")
+		buildExprs(or.Exprs, builder, OrWithSpace)
 	}
 }
 
@@ -156,7 +161,7 @@ func (not NotConditions) Build(builder Builder) {
 
 	for idx, c := range not.Exprs {
 		if idx > 0 {
-			builder.WriteString(" AND ")
+			builder.WriteString(AndWithSpace)
 		}
 
 		if negationBuilder, ok := c.(NegationExpressionBuilder); ok {
@@ -165,8 +170,8 @@ func (not NotConditions) Build(builder Builder) {
 			builder.WriteString("NOT ")
 			e, wrapInParentheses := c.(Expr)
 			if wrapInParentheses {
-				sql := strings.ToLower(e.SQL)
-				if wrapInParentheses = strings.Contains(sql, "and") || strings.Contains(sql, "or"); wrapInParentheses {
+				sql := strings.ToUpper(e.SQL)
+				if wrapInParentheses = strings.Contains(sql, AndWithSpace) || strings.Contains(sql, OrWithSpace); wrapInParentheses {
 					builder.WriteByte('(')
 				}
 			}
diff --git a/errors.go b/errors.go
index 145614d..49cbfe6 100644
--- a/errors.go
+++ b/errors.go
@@ -39,4 +39,6 @@ var (
 	ErrInvalidValue = errors.New("invalid value, should be pointer to struct or slice")
 	// ErrInvalidValueOfLength invalid values do not match length
 	ErrInvalidValueOfLength = errors.New("invalid association values, length doesn't match")
+	// ErrPreloadNotAllowed preload is not allowed when count is used
+	ErrPreloadNotAllowed = errors.New("preload is not allowed when count is used")
 )
diff --git a/finisher_api.go b/finisher_api.go
index 355d89b..f994ec3 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))
 								}
 							}
 						}
@@ -255,7 +255,7 @@ func (tx *DB) assignInterfacesToValue(values ...interface{}) {
 		}
 	}
 }
-
+// FirstOrInit gets the first matched record or initialize a new instance with given conditions (only works with struct or map conditions)
 func (db *DB) FirstOrInit(dest interface{}, conds ...interface{}) (tx *DB) {
 	queryTx := db.Limit(1).Order(clause.OrderByColumn{
 		Column: clause.Column{Table: clause.CurrentTable, Name: clause.PrimaryKey},
@@ -281,6 +281,7 @@ func (db *DB) FirstOrInit(dest interface{}, conds ...interface{}) (tx *DB) {
 	return
 }
 
+// FirstOrCreate gets the first matched record or create a new one with given conditions (only works with struct, map conditions)
 func (db *DB) FirstOrCreate(dest interface{}, conds ...interface{}) (tx *DB) {
 	queryTx := db.Limit(1).Order(clause.OrderByColumn{
 		Column: clause.Column{Table: clause.CurrentTable, Name: clause.PrimaryKey},
@@ -367,6 +368,10 @@ func (db *DB) Delete(value interface{}, conds ...interface{}) (tx *DB) {
 
 func (db *DB) Count(count *int64) (tx *DB) {
 	tx = db.getInstance()
+	if len(tx.Statement.Preloads) > 0 {
+		tx.AddError(ErrPreloadNotAllowed)
+		return
+	}
 	if tx.Statement.Model == nil {
 		tx.Statement.Model = tx.Statement.Dest
 		defer func() {
@@ -585,7 +590,7 @@ func (db *DB) Transaction(fc func(tx *DB) error, opts ...*sql.TxOptions) (err er
 func (db *DB) Begin(opts ...*sql.TxOptions) *DB {
 	var (
 		// clone statement
-		tx  = db.getInstance().Session(&Session{Context: db.Statement.Context})
+		tx  = db.getInstance().Session(&Session{Context: db.Statement.Context, NewDB: db.clone == 1})
 		opt *sql.TxOptions
 		err error
 	)
diff --git a/gorm.go b/gorm.go
index fc70f68..7967b09 100644
--- a/gorm.go
+++ b/gorm.go
@@ -59,6 +59,7 @@ type Config struct {
 	cacheStore *sync.Map
 }
 
+// Apply update config to new config
 func (c *Config) Apply(config *Config) error {
 	if config != c {
 		*config = *c
@@ -66,6 +67,7 @@ func (c *Config) Apply(config *Config) error {
 	return nil
 }
 
+// AfterInitialize initialize plugins after db connected
 func (c *Config) AfterInitialize(db *DB) error {
 	if db != nil {
 		for _, plugin := range c.Plugins {
@@ -77,6 +79,7 @@ func (c *Config) AfterInitialize(db *DB) error {
 	return nil
 }
 
+// Option gorm option interface
 type Option interface {
 	Apply(*Config) error
 	AfterInitialize(*DB) error
@@ -96,6 +99,7 @@ type Session struct {
 	DryRun                   bool
 	PrepareStmt              bool
 	NewDB                    bool
+	Initialized              bool
 	SkipHooks                bool
 	SkipDefaultTransaction   bool
 	DisableNestedTransaction bool
@@ -282,6 +286,10 @@ func (db *DB) Session(config *Session) *DB {
 		tx.Config.NowFunc = config.NowFunc
 	}
 
+	if config.Initialized {
+		tx = tx.getInstance()
+	}
+
 	return tx
 }
 
@@ -376,10 +384,12 @@ func (db *DB) getInstance() *DB {
 	return db
 }
 
+// Expr returns clause.Expr, which can be used to pass SQL expression as params
 func Expr(expr string, args ...interface{}) clause.Expr {
 	return clause.Expr{SQL: expr, Vars: args}
 }
 
+// SetupJoinTable setup join table schema
 func (db *DB) SetupJoinTable(model interface{}, field string, joinTable interface{}) error {
 	var (
 		tx                      = db.getInstance()
@@ -430,6 +440,7 @@ func (db *DB) SetupJoinTable(model interface{}, field string, joinTable interfac
 	return nil
 }
 
+// Use use plugin
 func (db *DB) Use(plugin Plugin) error {
 	name := plugin.Name()
 	if _, ok := db.Plugins[name]; ok {
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/logger/logger.go b/logger/logger.go
index 0c4ca4a..2ffd28d 100644
--- a/logger/logger.go
+++ b/logger/logger.go
@@ -12,6 +12,7 @@ import (
 	"gorm.io/gorm/utils"
 )
 
+// ErrRecordNotFound record not found error
 var ErrRecordNotFound = errors.New("record not found")
 
 // Colors
@@ -30,13 +31,17 @@ const (
 	YellowBold  = "\033[33;1m"
 )
 
-// LogLevel
+// LogLevel log level
 type LogLevel int
 
 const (
+	// Silent silent log level
 	Silent LogLevel = iota + 1
+	// Error error log level
 	Error
+	// Warn warn log level
 	Warn
+	// Info info log level
 	Info
 )
 
@@ -45,6 +50,7 @@ type Writer interface {
 	Printf(string, ...interface{})
 }
 
+// Config logger config
 type Config struct {
 	SlowThreshold             time.Duration
 	Colorful                  bool
@@ -62,16 +68,20 @@ type Interface interface {
 }
 
 var (
+	// Discard Discard logger will print any log to ioutil.Discard
 	Discard = New(log.New(ioutil.Discard, "", log.LstdFlags), Config{})
+	// Default Default logger
 	Default = New(log.New(os.Stdout, "\r\n", log.LstdFlags), Config{
 		SlowThreshold:             200 * time.Millisecond,
 		LogLevel:                  Warn,
 		IgnoreRecordNotFoundError: false,
 		Colorful:                  true,
 	})
+	// Recorder Recorder logger records running SQL into a recorder instance
 	Recorder = traceRecorder{Interface: Default, BeginAt: time.Now()}
 )
 
+// New initialize logger
 func New(writer Writer, config Config) Interface {
 	var (
 		infoStr      = "%s\n[info] "
@@ -179,10 +189,12 @@ type traceRecorder struct {
 	Err          error
 }
 
+// New new trace recorder
 func (l traceRecorder) New() *traceRecorder {
 	return &traceRecorder{Interface: l.Interface, BeginAt: time.Now()}
 }
 
+// Trace implement logger interface
 func (l *traceRecorder) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) {
 	l.BeginAt = begin
 	l.SQL, l.RowsAffected = fc()
diff --git a/logger/sql.go b/logger/sql.go
index 5ecb0ae..04a2dbd 100644
--- a/logger/sql.go
+++ b/logger/sql.go
@@ -19,9 +19,9 @@ const (
 	nullStr     = "NULL"
 )
 
-func isPrintable(s []byte) bool {
+func isPrintable(s string) bool {
 	for _, r := range s {
-		if !unicode.IsPrint(rune(r)) {
+		if !unicode.IsPrint(r) {
 			return false
 		}
 	}
@@ -30,9 +30,12 @@ func isPrintable(s []byte) bool {
 
 var convertibleTypes = []reflect.Type{reflect.TypeOf(time.Time{}), reflect.TypeOf(false), reflect.TypeOf([]byte{})}
 
+// ExplainSQL generate SQL string with given parameters, the generated SQL is expected to be used in logger, execute it might introduce a SQL injection vulnerability
 func ExplainSQL(sql string, numericPlaceholder *regexp.Regexp, escaper string, avars ...interface{}) string {
-	var convertParams func(interface{}, int)
-	vars := make([]string, len(avars))
+	var (
+		convertParams func(interface{}, int)
+		vars          = make([]string, len(avars))
+	)
 
 	convertParams = func(v interface{}, idx int) {
 		switch v := v.(type) {
@@ -64,14 +67,25 @@ func ExplainSQL(sql string, numericPlaceholder *regexp.Regexp, escaper string, a
 			}
 		case fmt.Stringer:
 			reflectValue := reflect.ValueOf(v)
-			if v != nil && reflectValue.IsValid() && ((reflectValue.Kind() == reflect.Ptr && !reflectValue.IsNil()) || reflectValue.Kind() != reflect.Ptr) {
+			switch reflectValue.Kind() {
+			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+				vars[idx] = fmt.Sprintf("%d", reflectValue.Interface())
+			case reflect.Float32, reflect.Float64:
+				vars[idx] = fmt.Sprintf("%.6f", reflectValue.Interface())
+			case reflect.Bool:
+				vars[idx] = fmt.Sprintf("%t", reflectValue.Interface())
+			case reflect.String:
 				vars[idx] = escaper + strings.Replace(fmt.Sprintf("%v", v), escaper, "\\"+escaper, -1) + escaper
-			} else {
-				vars[idx] = nullStr
+			default:
+				if v != nil && reflectValue.IsValid() && ((reflectValue.Kind() == reflect.Ptr && !reflectValue.IsNil()) || reflectValue.Kind() != reflect.Ptr) {
+					vars[idx] = escaper + strings.Replace(fmt.Sprintf("%v", v), escaper, "\\"+escaper, -1) + escaper
+				} else {
+					vars[idx] = nullStr
+				}
 			}
 		case []byte:
-			if isPrintable(v) {
-				vars[idx] = escaper + strings.Replace(string(v), escaper, "\\"+escaper, -1) + escaper
+			if s := string(v); isPrintable(s) {
+				vars[idx] = escaper + strings.ReplaceAll(s, escaper, "\\"+escaper) + escaper
 			} else {
 				vars[idx] = escaper + "<binary>" + escaper
 			}
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..cc1331b
--- /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
+	PrimaryKeyValue    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.PrimaryKeyValue.Bool, ct.PrimaryKeyValue.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 138917f..a50bb3f 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,10 +345,11 @@ 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 {
-			fileType := clause.Expr{SQL: m.DataTypeOf(field)}
+			fileType := m.FullDataTypeOf(field)
 			return m.DB.Exec(
 				"ALTER TABLE ? ALTER COLUMN ? TYPE ?",
 				m.CurrentTable(stmt), clause.Column{Name: field.DBName}, fileType,
@@ -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)
@@ -421,6 +436,30 @@ func (m Migrator) MigrateColumn(value interface{}, field *schema.Field, columnTy
 		}
 	}
 
+	// check unique
+	if unique, ok := columnType.Unique(); ok && unique != field.Unique {
+		// not primary key
+		if !field.PrimaryKey {
+			alterColumn = true
+		}
+	}
+
+	// check default value
+	if v, ok := columnType.DefaultValue(); ok && v != field.DefaultValue {
+		// not primary key
+		if !field.PrimaryKey {
+			alterColumn = true
+		}
+	}
+
+	// check comment
+	if comment, ok := columnType.Comment(); ok && comment != field.Comment {
+		// not primary key
+		if !field.PrimaryKey {
+			alterColumn = true
+		}
+	}
+
 	if alterColumn && !field.IgnoreMigration {
 		return m.DB.Migrator().AlterColumn(value, field.Name)
 	}
@@ -448,7 +487,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 +496,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 +528,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 +573,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 +597,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 +610,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 +631,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 +653,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 +690,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 +701,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 +719,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 +729,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 +833,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/naming.go b/schema/naming.go
index 8407bff..a4e3a75 100644
--- a/schema/naming.go
+++ b/schema/naming.go
@@ -120,7 +120,13 @@ func (ns NamingStrategy) toDBName(name string) string {
 	}
 
 	if ns.NameReplacer != nil {
-		name = ns.NameReplacer.Replace(name)
+		tmpName := ns.NameReplacer.Replace(name)
+
+		if tmpName == "" {
+			return name
+		}
+
+		name = tmpName
 	}
 
 	if ns.NoLowerCase {
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 146722a..cb47177 100644
--- a/statement.go
+++ b/statement.go
@@ -179,9 +179,7 @@ func (stmt *Statement) AddVar(writer clause.Writer, vars ...interface{}) {
 			} else {
 				stmt.AddVar(writer, v.GormValue(stmt.Context, stmt.DB))
 			}
-		case clause.Expr:
-			v.Build(stmt)
-		case *clause.Expr:
+		case clause.Expression:
 			v.Build(stmt)
 		case driver.Valuer:
 			stmt.Vars = append(stmt.Vars, v)
@@ -391,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 != "" {
@@ -405,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 != "" {
@@ -564,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)
 				}
@@ -574,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() {
@@ -585,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)
@@ -605,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 {
@@ -619,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/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 700af75..91a0abc 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -33,7 +33,7 @@ jobs:
         key: ${{ runner.os }}-go-${{ matrix.go }}-${{ hashFiles('tests/go.mod') }}
 
     - name: Tests
-      run: GORM_DIALECT=sqlite ./tests/tests_all.sh
+      run: GITHUB_ACTION=true GORM_DIALECT=sqlite ./tests/tests_all.sh
 
   mysql:
     strategy:
@@ -77,7 +77,7 @@ jobs:
         key: ${{ runner.os }}-go-${{ matrix.go }}-${{ hashFiles('tests/go.mod') }}
 
     - name: Tests
-      run: GORM_DIALECT=mysql GORM_DSN="gorm:gorm@tcp(localhost:9910)/gorm?charset=utf8&parseTime=True" ./tests/tests_all.sh
+      run: GITHUB_ACTION=true GORM_DIALECT=mysql GORM_DSN="gorm:gorm@tcp(localhost:9910)/gorm?charset=utf8&parseTime=True" ./tests/tests_all.sh
 
   postgres:
     strategy:
@@ -120,7 +120,7 @@ jobs:
         key: ${{ runner.os }}-go-${{ matrix.go }}-${{ hashFiles('tests/go.mod') }}
 
     - name: Tests
-      run: GORM_DIALECT=postgres GORM_DSN="user=gorm password=gorm dbname=gorm host=localhost port=9920 sslmode=disable TimeZone=Asia/Shanghai" ./tests/tests_all.sh
+      run: GITHUB_ACTION=true GORM_DIALECT=postgres GORM_DSN="user=gorm password=gorm dbname=gorm host=localhost port=9920 sslmode=disable TimeZone=Asia/Shanghai" ./tests/tests_all.sh
 
   sqlserver:
     strategy:
@@ -163,4 +163,4 @@ jobs:
         key: ${{ runner.os }}-go-${{ matrix.go }}-${{ hashFiles('tests/go.mod') }}
 
     - name: Tests
-      run: GORM_DIALECT=sqlserver GORM_DSN="sqlserver://gorm:LoremIpsum86@localhost:9930?database=gorm" ./tests/tests_all.sh
+      run: GITHUB_ACTION=true GORM_DIALECT=sqlserver GORM_DSN="sqlserver://gorm:LoremIpsum86@localhost:9930?database=gorm" ./tests/tests_all.sh
diff --git a/clause/select_test.go b/clause/select_test.go
index 9fce078..18bc269 100644
--- a/clause/select_test.go
+++ b/clause/select_test.go
@@ -43,6 +43,23 @@ func TestSelect(t *testing.T) {
 			}, clause.From{}},
 			"SELECT `id`, `name`, LENGTH(`mobile`) FROM `users`", nil,
 		},
+		{
+			[]clause.Interface{clause.Select{
+				Expression: clause.CommaExpression{
+					Exprs: []clause.Expression{
+						clause.Expr{
+							SQL: "? as name",
+							Vars: []interface{}{clause.Eq{
+								Column: clause.Column{Name: "age"},
+								Value:  18,
+							},
+							},
+						},
+					},
+				},
+			}, clause.From{}},
+			"SELECT `age` = ? as name FROM `users`", []interface{}{18},
+		},
 	}
 
 	for idx, result := range results {
diff --git a/clause/where_test.go b/clause/where_test.go
index 272c7b7..35e3dbe 100644
--- a/clause/where_test.go
+++ b/clause/where_test.go
@@ -66,6 +66,45 @@ func TestWhere(t *testing.T) {
 			"SELECT * FROM `users` WHERE (`age` = ? OR `name` <> ?)",
 			[]interface{}{18, "jinzhu"},
 		},
+		{
+			[]clause.Interface{clause.Select{}, clause.From{}, clause.Where{
+				Exprs: []clause.Expression{clause.Not(clause.Eq{Column: clause.PrimaryColumn, Value: "1"}, clause.Gt{Column: "age", Value: 18}), clause.And(clause.Expr{SQL: "`score` <= ?", Vars: []interface{}{100}, WithoutParentheses: false})},
+			}},
+			"SELECT * FROM `users` WHERE (`users`.`id` <> ? AND `age` <= ?) AND `score` <= ?",
+			[]interface{}{"1", 18, 100},
+		},
+		{
+			[]clause.Interface{clause.Select{}, clause.From{}, clause.Where{
+				Exprs: []clause.Expression{clause.Not(clause.Eq{Column: clause.PrimaryColumn, Value: "1"}, clause.Gt{Column: "age", Value: 18}), clause.Expr{SQL: "`score` <= ?", Vars: []interface{}{100}, WithoutParentheses: false}},
+			}},
+			"SELECT * FROM `users` WHERE (`users`.`id` <> ? AND `age` <= ?) AND `score` <= ?",
+			[]interface{}{"1", 18, 100},
+		},
+		{
+			[]clause.Interface{clause.Select{}, clause.From{}, clause.Where{
+				Exprs: []clause.Expression{clause.Not(clause.Eq{Column: clause.PrimaryColumn, Value: "1"}, clause.Gt{Column: "age", Value: 18}), clause.Or(clause.Expr{SQL: "`score` <= ?", Vars: []interface{}{100}, WithoutParentheses: false})},
+			}},
+			"SELECT * FROM `users` WHERE (`users`.`id` <> ? AND `age` <= ?) OR `score` <= ?",
+			[]interface{}{"1", 18, 100},
+		},
+		{
+			[]clause.Interface{clause.Select{}, clause.From{}, clause.Where{
+				Exprs: []clause.Expression{
+					clause.And(clause.Not(clause.Eq{Column: clause.PrimaryColumn, Value: "1"}),
+						clause.And(clause.Expr{SQL: "`score` <= ?", Vars: []interface{}{100}, WithoutParentheses: false})),
+				},
+			}},
+			"SELECT * FROM `users` WHERE (`users`.`id` <> ? AND `score` <= ?)",
+			[]interface{}{"1", 100},
+		},
+		{
+			[]clause.Interface{clause.Select{}, clause.From{}, clause.Where{
+				Exprs: []clause.Expression{clause.Not(clause.Eq{Column: clause.PrimaryColumn, Value: "1"},
+					clause.And(clause.Expr{SQL: "`score` <= ?", Vars: []interface{}{100}, WithoutParentheses: false}))},
+			}},
+			"SELECT * FROM `users` WHERE (`users`.`id` <> ? AND NOT `score` <= ?)",
+			[]interface{}{"1", 100},
+		},
 	}
 
 	for idx, result := range results {
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/naming_test.go b/schema/naming_test.go
index c3e6bf9..1fdab9a 100644
--- a/schema/naming_test.go
+++ b/schema/naming_test.go
@@ -197,3 +197,14 @@ func TestFormatNameWithStringLongerThan64Characters(t *testing.T) {
 		t.Errorf("invalid formatted name generated, got %v", formattedName)
 	}
 }
+
+func TestReplaceEmptyTableName(t *testing.T) {
+	ns := NamingStrategy{
+		SingularTable: true,
+		NameReplacer:  strings.NewReplacer("Model", ""),
+	}
+	tableName := ns.TableName("Model")
+	if tableName != "Model" {
+		t.Errorf("invalid table name generated, got %v", tableName)
+	}
+}
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/connection_test.go b/tests/connection_test.go
index 92b13dd..7bc2300 100644
--- a/tests/connection_test.go
+++ b/tests/connection_test.go
@@ -9,7 +9,7 @@ import (
 )
 
 func TestWithSingleConnection(t *testing.T) {
-	var expectedName = "test"
+	expectedName := "test"
 	var actualName string
 
 	setSQL, getSQL := getSetSQL(DB.Dialector.Name())
@@ -27,7 +27,6 @@ func TestWithSingleConnection(t *testing.T) {
 		}
 		return nil
 	})
-
 	if err != nil {
 		t.Errorf(fmt.Sprintf("WithSingleConnection should work, but got err %v", err))
 	}
diff --git a/tests/count_test.go b/tests/count_test.go
index 27d7ee6..b63a55f 100644
--- a/tests/count_test.go
+++ b/tests/count_test.go
@@ -144,4 +144,14 @@ func TestCount(t *testing.T) {
 	if err := DB.Model(&User{}).Where("name = ?", "count-4").Group("name").Count(&count11).Error; err != nil || count11 != 1 {
 		t.Fatalf("Count should be 3, but got count: %v err %v", count11, err)
 	}
+
+	var count12 int64
+	if err := DB.Table("users").
+		Where("name in ?", []string{user1.Name, user2.Name, user3.Name}).
+		Preload("Toys", func(db *gorm.DB) *gorm.DB {
+			return db.Table("toys").Select("name")
+		}).Count(&count12).Error; err != gorm.ErrPreloadNotAllowed {
+		t.Errorf("should returns preload not allowed error, but got %v", err)
+	}
+	
 }
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/docker-compose.yml b/tests/docker-compose.yml
index 05e0956..9ab4ddb 100644
--- a/tests/docker-compose.yml
+++ b/tests/docker-compose.yml
@@ -2,7 +2,7 @@ version: '3'
 
 services:
   mysql:
-    image: 'mysql:latest'
+    image: 'mysql/mysql-server:latest'
     ports:
       - 9910:3306
     environment:
@@ -20,7 +20,7 @@ services:
       - POSTGRES_USER=gorm
       - POSTGRES_PASSWORD=gorm
   mssql:
-    image: 'mcmoe/mssqldocker:latest'
+    image: '${MSSQL_IMAGE:-mcmoe/mssqldocker}:latest'
     ports:
       - 9930:1433
     environment:
diff --git a/tests/go.mod b/tests/go.mod
index 3233ea9..1c1fb23 100644
--- a/tests/go.mod
+++ b/tests/go.mod
@@ -4,15 +4,16 @@ go 1.14
 
 require (
 	github.com/google/uuid v1.3.0
-	github.com/jackc/pgx/v4 v4.14.1 // indirect
+	github.com/jackc/pgx/v4 v4.15.0 // indirect
 	github.com/jinzhu/now v1.1.4
 	github.com/lib/pq v1.10.4
-	golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b // 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
-	gorm.io/gorm v1.22.4
+	github.com/mattn/go-sqlite3 v1.14.11 // indirect
+	golang.org/x/crypto v0.0.0-20220214200702-86341886e292 // indirect
+	gorm.io/driver/mysql v1.3.1
+	gorm.io/driver/postgres v1.3.1
+	gorm.io/driver/sqlite v1.3.1
+	gorm.io/driver/sqlserver v1.3.1
+	gorm.io/gorm v1.23.0
 )
 
 replace gorm.io/gorm => ../
diff --git a/tests/joins_test.go b/tests/joins_test.go
index e276a74..4c9cffa 100644
--- a/tests/joins_test.go
+++ b/tests/joins_test.go
@@ -158,6 +158,22 @@ func TestJoinsWithSelect(t *testing.T) {
 	}
 }
 
+func TestJoinWithOmit(t *testing.T) {
+	user := *GetUser("joins_with_omit", Config{Pets: 2})
+	DB.Save(&user)
+
+	results := make([]*User, 0)
+
+	if err := DB.Table("users").Omit("name").Where("users.name = ?", "joins_with_omit").Joins("left join pets on pets.user_id = users.id").Find(&results).Error; err != nil {
+		return
+	}
+
+	if len(results) != 2 || results[0].Name != "" || results[1].Name != "" {
+		t.Errorf("Should find all two pets with Join omit and should not find user's name, got %+v", results)
+		return
+	}
+}
+
 func TestJoinCount(t *testing.T) {
 	companyA := Company{Name: "A"}
 	companyB := Company{Name: "B"}
diff --git a/tests/migrate_test.go b/tests/migrate_test.go
index aa0a84a..94f562b 100644
--- a/tests/migrate_test.go
+++ b/tests/migrate_test.go
@@ -45,7 +45,7 @@ func TestMigrate(t *testing.T) {
 
 	for _, m := range allModels {
 		if !DB.Migrator().HasTable(m) {
-			t.Fatalf("Failed to create table for %#v---", m)
+			t.Fatalf("Failed to create table for %#v", m)
 		}
 	}
 
@@ -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,16 @@ func TestMigrateIndexes(t *testing.T) {
 }
 
 func TestMigrateColumns(t *testing.T) {
+	sqlite := DB.Dialector.Name() == "sqlite"
+	sqlserver := DB.Dialector.Name() == "sqlserver"
+
 	type ColumnStruct struct {
 		gorm.Model
-		Name string
+		Name  string
+		Age   int    `gorm:"default:18;comment:my age"`
+		Code  string `gorm:"unique;comment:my code;"`
+		Code2 string
+		Code3 string `gorm:"unique"`
 	}
 
 	DB.Migrator().DropTable(&ColumnStruct{})
@@ -326,13 +333,20 @@ func TestMigrateColumns(t *testing.T) {
 
 	type ColumnStruct2 struct {
 		gorm.Model
-		Name string `gorm:"size:100"`
+		Name  string `gorm:"size:100"`
+		Code  string `gorm:"unique;comment:my code2;default:hello"`
+		Code2 string `gorm:"unique"`
+		// Code3 string
 	}
 
-	if err := DB.Table("column_structs").Migrator().AlterColumn(&ColumnStruct2{}, "Name"); err != nil {
+	if err := DB.Table("column_structs").Migrator().AlterColumn(&ColumnStruct{}, "Name"); err != nil {
 		t.Fatalf("no error should happened when alter column, but got %v", err)
 	}
 
+	if err := DB.Table("column_structs").AutoMigrate(&ColumnStruct2{}); err != nil {
+		t.Fatalf("no error should happened when auto migrate column, but got %v", err)
+	}
+
 	if columnTypes, err := DB.Migrator().ColumnTypes(&ColumnStruct{}); err != nil {
 		t.Fatalf("no error should returns for ColumnTypes")
 	} else {
@@ -340,11 +354,45 @@ 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(); !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(); !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(); !ok || v != "18" {
+					t.Fatalf("column age default value should be correct, name: %v, column: %#v", columnType.Name(), columnType)
+				}
+				if v, ok := columnType.Comment(); !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(); !ok || !v {
+					t.Fatalf("column code unique should be correct, name: %v, column: %#v", columnType.Name(), columnType)
+				}
+				if v, ok := columnType.DefaultValue(); !sqlserver && (!ok || v != "hello") {
+					t.Fatalf("column code default value should be correct, name: %v, column: %#v", columnType.Name(), columnType)
+				}
+				if v, ok := columnType.Comment(); !sqlite && !sqlserver && (!ok || v != "my code2") {
+					t.Fatalf("column code comment should be correct, name: %v, column: %#v", columnType.Name(), columnType)
+				}
+			case "code2":
+				if v, ok := columnType.Unique(); !sqlserver && (!ok || !v) {
+					t.Fatalf("column code2 unique should be correct, name: %v, column: %#v", columnType.Name(), columnType)
 				}
+			case "code3":
+				// TODO
+				// if v, ok := columnType.Unique(); !ok || v {
+				// 	t.Fatalf("column code unique should be correct, name: %v, column: %#v", columnType.Name(), columnType)
+				// }
 			}
 		}
 	}
diff --git a/tests/query_test.go b/tests/query_test.go
index c99214b..d10df18 100644
--- a/tests/query_test.go
+++ b/tests/query_test.go
@@ -512,7 +512,13 @@ func TestNotWithAllFields(t *testing.T) {
 func TestOr(t *testing.T) {
 	dryDB := DB.Session(&gorm.Session{DryRun: true})
 
-	result := dryDB.Where("role = ?", "admin").Where(DB.Or("role = ?", "super_admin")).Find(&User{})
+	var count int64
+	result := dryDB.Model(&User{}).Or("role = ?", "admin").Count(&count)
+	if !regexp.MustCompile("SELECT count\\(\\*\\) FROM .*users.* WHERE role = .+ AND .*users.*\\..*deleted_at.* IS NULL").MatchString(result.Statement.SQL.String()) {
+		t.Fatalf("Build OR condition, but got %v", result.Statement.SQL.String())
+	}
+
+	result = dryDB.Where("role = ?", "admin").Where(DB.Or("role = ?", "super_admin")).Find(&User{})
 	if !regexp.MustCompile("SELECT \\* FROM .*users.* WHERE .*role.* = .+ AND .*role.* = .+").MatchString(result.Statement.SQL.String()) {
 		t.Fatalf("Build OR condition, but got %v", result.Statement.SQL.String())
 	}
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)
+}
diff --git a/tests/sql_builder_test.go b/tests/sql_builder_test.go
index 237d807..897f687 100644
--- a/tests/sql_builder_test.go
+++ b/tests/sql_builder_test.go
@@ -168,6 +168,59 @@ func TestDryRun(t *testing.T) {
 	}
 }
 
+type ageInt int8
+
+func (ageInt) String() string {
+	return "age"
+}
+
+type ageBool bool
+
+func (ageBool) String() string {
+	return "age"
+}
+
+type ageUint64 uint64
+
+func (ageUint64) String() string {
+	return "age"
+}
+
+type ageFloat float64
+
+func (ageFloat) String() string {
+	return "age"
+}
+
+func TestExplainSQL(t *testing.T) {
+	user := *GetUser("explain-sql", Config{})
+	dryRunDB := DB.Session(&gorm.Session{DryRun: true})
+
+	stmt := dryRunDB.Model(&user).Where("id = ?", 1).Updates(map[string]interface{}{"age": ageInt(8)}).Statement
+	sql := DB.Dialector.Explain(stmt.SQL.String(), stmt.Vars...)
+	if !regexp.MustCompile(`.*age.*=8,`).MatchString(sql) {
+		t.Errorf("Failed to generate sql, got %v", sql)
+	}
+
+	stmt = dryRunDB.Model(&user).Where("id = ?", 1).Updates(map[string]interface{}{"age": ageUint64(10241024)}).Statement
+	sql = DB.Dialector.Explain(stmt.SQL.String(), stmt.Vars...)
+	if !regexp.MustCompile(`.*age.*=10241024,`).MatchString(sql) {
+		t.Errorf("Failed to generate sql, got %v", sql)
+	}
+
+	stmt = dryRunDB.Model(&user).Where("id = ?", 1).Updates(map[string]interface{}{"age": ageBool(false)}).Statement
+	sql = DB.Dialector.Explain(stmt.SQL.String(), stmt.Vars...)
+	if !regexp.MustCompile(`.*age.*=false,`).MatchString(sql) {
+		t.Errorf("Failed to generate sql, got %v", sql)
+	}
+
+	stmt = dryRunDB.Model(&user).Where("id = ?", 1).Updates(map[string]interface{}{"age": ageFloat(0.12345678)}).Statement
+	sql = DB.Dialector.Explain(stmt.SQL.String(), stmt.Vars...)
+	if !regexp.MustCompile(`.*age.*=0.123457,`).MatchString(sql) {
+		t.Errorf("Failed to generate sql, got %v", sql)
+	}
+}
+
 func TestGroupConditions(t *testing.T) {
 	type Pizza struct {
 		ID   uint
diff --git a/tests/tests_all.sh b/tests/tests_all.sh
index 79e0b5b..5b9bae9 100755
--- a/tests/tests_all.sh
+++ b/tests/tests_all.sh
@@ -15,6 +15,25 @@ then
   cd ..
 fi
 
+# SqlServer for Mac M1
+if [[ -z $GITHUB_ACTION ]]; then
+  if [ -d tests ]
+  then
+    cd tests
+    if [[ $(uname -a) == *" arm64" ]]; then
+      MSSQL_IMAGE=mcr.microsoft.com/azure-sql-edge docker-compose start || true
+      go install github.com/microsoft/go-sqlcmd/cmd/sqlcmd@latest || true
+      SQLCMDPASSWORD=LoremIpsum86 sqlcmd -U sa -S localhost:9930 -Q "IF DB_ID('gorm') IS NULL CREATE DATABASE gorm" > /dev/null || true
+      SQLCMDPASSWORD=LoremIpsum86 sqlcmd -U sa -S localhost:9930 -Q "IF SUSER_ID (N'gorm') IS NULL CREATE LOGIN gorm WITH PASSWORD = 'LoremIpsum86';" > /dev/null || true
+      SQLCMDPASSWORD=LoremIpsum86 sqlcmd -U sa -S localhost:9930 -Q "IF USER_ID (N'gorm') IS NULL CREATE USER gorm FROM LOGIN gorm; ALTER SERVER ROLE sysadmin ADD MEMBER [gorm];" > /dev/null || true
+    else
+      docker-compose start
+    fi
+    cd ..
+  fi
+fi
+
+
 for dialect in "${dialects[@]}" ; do
   if [ "$GORM_DIALECT" = "" ] || [ "$GORM_DIALECT" = "${dialect}" ]
   then
diff --git a/tests/tests_test.go b/tests/tests_test.go
index e26f358..11b6f06 100644
--- a/tests/tests_test.go
+++ b/tests/tests_test.go
@@ -62,13 +62,14 @@ func OpenTestConnection() (db *gorm.DB, err error) {
 			PreferSimpleProtocol: true,
 		}), &gorm.Config{})
 	case "sqlserver":
-		// CREATE LOGIN gorm WITH PASSWORD = 'LoremIpsum86';
+		// go install github.com/microsoft/go-sqlcmd/cmd/sqlcmd@latest
+		// SQLCMDPASSWORD=LoremIpsum86 sqlcmd -U sa -S localhost:9930
 		// CREATE DATABASE gorm;
-		// USE gorm;
+		// GO
+		// CREATE LOGIN gorm WITH PASSWORD = 'LoremIpsum86';
 		// CREATE USER gorm FROM LOGIN gorm;
-		// sp_changedbowner 'gorm';
-		// npm install -g sql-cli
-		// mssql -u gorm -p LoremIpsum86 -d gorm -o 9930
+		// ALTER SERVER ROLE sysadmin ADD MEMBER [gorm];
+		// GO
 		log.Println("testing sqlserver...")
 		if dbDSN == "" {
 			dbDSN = "sqlserver://gorm:LoremIpsum86@localhost:9930?database=gorm"