Featured image of post Using gorm gen in go-zero

Using gorm gen in go-zero

The built-in sqlx in go-zero is too hard to use~

Since the built-in sqlx in go-zero is too cumbersome to use, and it’s unbearable to write so many magic strings, this article introduces how to integrate gorm into go-zero.

Code Implementation

// cmd/gen.go
package main

import (
	"fmt"
	"path"

	"gorm.io/driver/mysql"
	"gorm.io/gen"
	"gorm.io/gen/field"
	"gorm.io/gorm"
)

var (
	// Modify these when generating for other services
	mysqlDsn  = "xxx:xxx@tcp(127.0.0.1:3306)/xxx?charset=utf8mb4&loc=Local&parseTime=true"
	outPath   = path.Join("..", "app", "account", "model", "do")
	modelPath = "entity"
)

func main() {
	db, err := gorm.Open(mysql.Open(mysqlDsn))
	if err != nil {
		panic(fmt.Errorf("cannot establish db connection: %w", err))
	}

	g := gen.NewGenerator(gen.Config{
		OutPath:      outPath,
		ModelPkgPath: modelPath,
		Mode:         gen.WithDefaultQuery | gen.WithoutContext,
		FieldNullable: true,
		FieldSignable: true,
		FieldWithIndexTag: true,
		FieldWithTypeTag: true,
	})
	
	g.UseDB(db)

	autoUpdateTimeField := gen.FieldGORMTag("updated_at", func(tag field.GormTag) field.GormTag {
		tag.Set("column", "updated_at")
		tag.Set("type", "timestamp")
		tag.Set("autoUpdateTime", "")
		return tag
	})
	
	// ... (other field configurations)

	allModel := g.GenerateAllTable(fieldOpts...)
	g.ApplyBasic(allModel...)
	g.Execute()
}

Run cd cmd && go run gen.go to generate code.

Directory Structure

+---app
|   +---account
|      +---model
|           +---dao        # Custom DAO implementations
|           +---do         # Generated query methods
|           +---entity     # GORM model definitions
+---cmd
|   \---gen.go             # Code generator config
+---pkg
|   \---gorm.go            # Custom GORM configurations

Key components:

  • dao: Custom query implementations
  • do: Generated GORM query methods
  • entity: Database entity models
  • pkg/gorm.go: Custom logger and connection pool settings

Core Implementations

  1. Custom GORM Logger
// pkg/gorm.go
type GormLogger struct {
	SlowThreshold time.Duration
	Mode          string
}

func (l *GormLogger) Trace(ctx context.Context, begin time.Time, fc func() (sql string, rowsAffected int64), err error) {
	// Implementation details...
}
  1. Connection Pool Configuration
// app/account/rpc/internal/svc/servicecontext.go
func NewServiceContext(c config.Config) (*ServiceContext, error) {
	conn, err := gorm.Open(
		mysql.Open(c.DataSource),
		&gorm.Config{Logger: pkg.NewGormLogger(c.Mode)},
	)
	// Set connection pool parameters
}
  1. Snowflake ID Generation
// app/account/model/entity/hooks.go
func (data *AppHasAuth) BeforeCreate(tx *gorm.DB) error {
	data.ID = snowId // Generated via ID service
	return nil
}
  1. DAO Layer Example
// app/account/model/dao/apps.go
func (dao *appsDao) Find(ctx context.Context, id uint64) (*entity.App, error) {
	return do.App.WithContext(ctx).Where(do.App.ID.Eq(id)).Take()
}

Usage Example

// Business logic usage
result, err := dao.AppsDao.Find(context.Background(), 1)

This implementation demonstrates how to:

  1. Generate GORM models and query methods
  2. Integrate with go-zero’s service context
  3. Implement custom logging and connection pooling
  4. Add distributed ID generation hooks
  5. Create a clean DAO layer abstraction

The solution maintains go-zero’s microservice advantages while leveraging GORM’s developer-friendly features.