Selaa lähdekoodia

完成事务封装

yjp 1 vuosi sitten
vanhempi
commit
ffbe53e09e

+ 93 - 0
binding/entity_crud/transaction.go

@@ -0,0 +1,93 @@
+package entity_crud
+
+import (
+	"git.sxidc.com/go-framework/baize/binding"
+	"git.sxidc.com/go-framework/baize/binding/request"
+	"git.sxidc.com/go-framework/baize/binding/response"
+	"git.sxidc.com/go-framework/baize/domain"
+)
+
+func BindTransaction[O any](binder *binding.Binder, crud *Simple[O]) {
+	crud.bind(binder)
+}
+
+// Transaction 实体CRUD(可选择使用事务)的Bind参数
+type Transaction[O any] struct {
+	// 使用的领域实体,注意是Entity类型
+	Entity domain.Entity
+
+	// 表名
+	TableName string
+
+	// 选择要使用的数据库Executor
+	// DBExecutorOperations operations 数据库操作
+	// DBExecutorDataService data_service 数据服务
+	DBExecutorType string
+
+	// URL领域相对路径,如/class,后面会自动补充
+	DomainPath string
+
+	// 创建使用的DTO
+	CreateDTO request.DTO
+
+	// 删除使用的DTO,注意是WithID类型
+	DeleteDTO request.WithID
+
+	// 更新使用的DTO,注意是WithID类型
+	UpdateDTO request.WithID
+
+	// 查询使用的DTO,注意是Query类型
+	QueryDTO request.Query
+
+	// 根据ID查询使用的DTO,注意是WithID类型
+	QueryByIDDTO request.WithID
+}
+
+func (crud *Simple[O]) bind(binder *binding.Binder) {
+	dbExecutor := binder.ChooseDBExecutor(crud.DBExecutorType)
+
+	// 创建班级
+	binding.PostBind(binder, &binding.SimpleBindItem[string]{
+		Path:         crud.DomainPath + "/create",
+		ResponseFunc: response.SendIDResponse[string],
+		DTO:          crud.CreateDTO,
+		Objects:      []domain.Object{crud.Entity},
+		ServiceFunc:  CommonEntityCreate(crud.TableName, dbExecutor, nil),
+	})
+
+	// 删除班级
+	binding.DeleteBind(binder, &binding.SimpleBindItem[any]{
+		Path:         crud.DomainPath + "/:id/delete",
+		ResponseFunc: response.SendMsgResponse,
+		DTO:          crud.DeleteDTO,
+		Objects:      []domain.Object{crud.Entity},
+		ServiceFunc:  CommonEntityDelete(crud.TableName, dbExecutor, nil),
+	})
+
+	// 修改班级
+	binding.PutBind(binder, &binding.SimpleBindItem[any]{
+		Path:         crud.DomainPath + "/update",
+		ResponseFunc: response.SendMsgResponse,
+		DTO:          crud.UpdateDTO,
+		Objects:      []domain.Object{crud.Entity},
+		ServiceFunc:  CommonEntityUpdate(crud.TableName, dbExecutor, nil),
+	})
+
+	// 查询班级
+	binding.GetBind(binder, &binding.SimpleBindItem[response.InfosData[O]]{
+		Path:         crud.DomainPath + "/query",
+		ResponseFunc: response.SendInfosResponse[O],
+		DTO:          crud.QueryDTO,
+		Objects:      []domain.Object{crud.Entity},
+		ServiceFunc:  CommonEntityQuery[O](crud.TableName, dbExecutor, nil, nil),
+	})
+
+	// 通过ID获取班级
+	binding.GetBind(binder, &binding.SimpleBindItem[O]{
+		Path:         crud.DomainPath + "/get",
+		ResponseFunc: response.SendInfoResponse[O],
+		DTO:          crud.QueryByIDDTO,
+		Objects:      []domain.Object{crud.Entity},
+		ServiceFunc:  CommonEntityQueryByID[O](crud.TableName, dbExecutor, nil),
+	})
+}

+ 236 - 0
binding/entity_crud/transaction_service.go

@@ -0,0 +1,236 @@
+package entity_crud
+
+import (
+	"git.sxidc.com/go-framework/baize/api"
+	"git.sxidc.com/go-framework/baize/binding"
+	"git.sxidc.com/go-framework/baize/binding/request"
+	"git.sxidc.com/go-framework/baize/binding/response"
+	"git.sxidc.com/go-framework/baize/domain"
+	"git.sxidc.com/go-framework/baize/infrastructure"
+	"git.sxidc.com/go-framework/baize/infrastructure/database"
+	"git.sxidc.com/go-framework/baize/infrastructure/database/sql"
+	"git.sxidc.com/go-framework/baize/tag/sql/sql_mapping"
+	"git.sxidc.com/go-tools/utils/strutils"
+	"git.sxidc.com/service-supports/fserr"
+	"reflect"
+)
+
+func CommonEntityCreate(tableName string, dbExecutor database.Executor, callbacks *Callbacks[string]) binding.ServiceFunc[string] {
+	return func(c *api.Context, dto request.DTO, objects []domain.Object, i *infrastructure.Infrastructure) (string, error) {
+		e, ok := objects[0].(domain.Entity)
+		if !ok {
+			return "", fserr.New("需要传递领域对象应该为实体")
+		}
+
+		err := e.GenerateID()
+		if err != nil {
+			return callbackOnError(callbacks, e, err, dbExecutor, "")
+		}
+
+		err = callbackBeforeDBOperate(callbacks, e, dbExecutor)
+		if err != nil {
+			return callbackOnError(callbacks, e, err, dbExecutor, "")
+		}
+
+		err = database.InsertEntity(dbExecutor, tableName, e)
+		if err != nil {
+			if database.IsErrorDBRecordHasExist(err) {
+				err = fserr.New(e.DomainCNName() + "已存在")
+			}
+
+			return callbackOnError(callbacks, e, err, dbExecutor, "")
+		}
+
+		return callbackOnReturn(callbacks, e, dbExecutor, e.GetID())
+	}
+}
+
+func CommonEntityDelete(tableName string, dbExecutor database.Executor, callbacks *Callbacks[any]) binding.ServiceFunc[any] {
+	return func(c *api.Context, dto request.DTO, objects []domain.Object, i *infrastructure.Infrastructure) (any, error) {
+		e, ok := objects[0].(domain.Entity)
+		if !ok {
+			return nil, fserr.New("需要传递领域对象应该为实体")
+		}
+
+		if strutils.IsStringEmpty(e.GetID()) {
+			err := fserr.New("领域实体ID为空")
+			return callbackOnError(callbacks, e, err, dbExecutor, nil)
+		}
+
+		exist, err := database.CheckExist(dbExecutor, &sql.CheckExistExecuteParams{
+			TableName:  tableName,
+			Conditions: sql.NewConditions().Equal(e.IDColumnName(), e.GetID()),
+		})
+		if err != nil {
+			return callbackOnError(callbacks, e, err, dbExecutor, nil)
+		}
+
+		if !exist {
+			err := fserr.New(e.DomainCNName() + "不存在")
+			return callbackOnError(callbacks, e, err, dbExecutor, nil)
+		}
+
+		err = callbackBeforeDBOperate(callbacks, e, dbExecutor)
+		if err != nil {
+			return callbackOnError(callbacks, e, err, dbExecutor, nil)
+		}
+
+		err = database.DeleteEntity(dbExecutor, tableName, e)
+		if err != nil {
+			return callbackOnError(callbacks, e, err, dbExecutor, nil)
+		}
+
+		return callbackOnReturn(callbacks, e, dbExecutor, nil)
+	}
+}
+
+func CommonEntityUpdate(tableName string, dbExecutor database.Executor, callbacks *Callbacks[any]) binding.ServiceFunc[any] {
+	return func(c *api.Context, dto request.DTO, objects []domain.Object, i *infrastructure.Infrastructure) (any, error) {
+		e, ok := objects[0].(domain.Entity)
+		if !ok {
+			return nil, fserr.New("需要传递领域对象应该为实体")
+		}
+
+		if strutils.IsStringEmpty(e.GetID()) {
+			err := fserr.New("领域实体ID为空")
+			return callbackOnError(callbacks, e, err, dbExecutor, nil)
+		}
+
+		exist, err := database.CheckExist(dbExecutor, &sql.CheckExistExecuteParams{
+			TableName:  tableName,
+			Conditions: sql.NewConditions().Equal(e.IDColumnName(), e.GetID()),
+		})
+		if err != nil {
+			return callbackOnError(callbacks, e, err, dbExecutor, nil)
+		}
+
+		if !exist {
+			err := fserr.New(e.DomainCNName() + "不存在")
+			return callbackOnError(callbacks, e, err, dbExecutor, nil)
+		}
+
+		err = callbackBeforeDBOperate(callbacks, e, dbExecutor)
+		if err != nil {
+			return callbackOnError(callbacks, e, err, dbExecutor, nil)
+		}
+
+		err = database.UpdateEntity(dbExecutor, tableName, e)
+		if err != nil {
+			return callbackOnError(callbacks, e, err, dbExecutor, nil)
+		}
+
+		return callbackOnReturn(callbacks, e, dbExecutor, nil)
+	}
+}
+
+func CommonEntityQuery[O any](tableName string, dbExecutor database.Executor, callbacks *Callbacks[response.InfosData[O]], conditionFieldCallback domain.ConditionFieldCallback) binding.ServiceFunc[response.InfosData[O]] {
+	return func(c *api.Context, dto request.DTO, objects []domain.Object, i *infrastructure.Infrastructure) (response.InfosData[O], error) {
+		queryDTO, ok := dto.(request.Query)
+		if !ok {
+			return response.InfosData[O]{}, fserr.New("DTO不是Query")
+		}
+
+		e, ok := objects[0].(domain.Entity)
+		if !ok {
+			return response.InfosData[O]{}, fserr.New("需要传递领域对象应该为实体")
+		}
+
+		conditions := sql.NewConditions()
+
+		fields, err := sql_mapping.DefaultUsage(e)
+		if err != nil {
+			return response.InfosData[O]{}, err
+		}
+
+		for _, field := range fields {
+			hasDeal := false
+			if conditionFieldCallback != nil {
+				hasDeal = conditionFieldCallback(conditions, field.FieldName, field.ColumnName, field.Value)
+			}
+
+			if !hasDeal {
+				fieldValue := reflect.ValueOf(field.Value)
+				if !fieldValue.IsZero() {
+					conditions.Equal(field.ColumnName, field.Value)
+				}
+			}
+		}
+
+		err = callbackBeforeDBOperate(callbacks, e, dbExecutor)
+		if err != nil {
+			return callbackOnError(callbacks, e, err, dbExecutor, response.InfosData[O]{})
+		}
+
+		results, totalCount, err := database.Query(dbExecutor, &sql.QueryExecuteParams{
+			TableName:  tableName,
+			Conditions: conditions,
+			PageNo:     queryDTO.GetPageNo(),
+			PageSize:   queryDTO.GetPageSize(),
+		})
+		if err != nil {
+			return callbackOnError(callbacks, e, err, dbExecutor, response.InfosData[O]{})
+		}
+
+		infos := make([]O, 0)
+		err = sql.ParseSqlResult(results, &infos)
+		if err != nil {
+			return callbackOnError(callbacks, e, err, dbExecutor, response.InfosData[O]{})
+		}
+
+		output := response.InfosData[O]{
+			Infos:      infos,
+			TotalCount: totalCount,
+			PageNo:     queryDTO.GetPageNo(),
+		}
+
+		return callbackOnReturn(callbacks, e, dbExecutor, output)
+	}
+}
+
+func CommonEntityQueryByID[O any](tableName string, dbExecutor database.Executor, callbacks *Callbacks[O]) binding.ServiceFunc[O] {
+	return func(c *api.Context, dto request.DTO, objects []domain.Object, i *infrastructure.Infrastructure) (O, error) {
+		var outputZero O
+		outputZeroValue := reflect.Zero(reflect.TypeOf(outputZero))
+		if outputZeroValue.Kind() == reflect.Pointer {
+			outputZeroValue.Set(reflect.New(outputZeroValue.Type().Elem()))
+		}
+
+		e, ok := objects[0].(domain.Entity)
+		if !ok {
+			return outputZero, fserr.New("需要传递领域对象应该为实体")
+		}
+
+		if strutils.IsStringEmpty(e.GetID()) {
+			err := fserr.New("领域实体ID为空")
+			return callbackOnError(callbacks, e, err, dbExecutor, outputZero)
+		}
+
+		err := callbackBeforeDBOperate(callbacks, e, dbExecutor)
+		if err != nil {
+			return callbackOnError(callbacks, e, err, dbExecutor, outputZero)
+		}
+
+		result, err := database.QueryOne(dbExecutor, &sql.QueryOneExecuteParams{
+			TableName:  tableName,
+			Conditions: sql.NewConditions().Equal(e.IDColumnName(), e.GetID()),
+		})
+		if err != nil {
+			return callbackOnError(callbacks, e, err, dbExecutor, outputZero)
+		}
+
+		var info O
+		var infoPointer any
+
+		infoPointer = &info
+		if outputZeroValue.Kind() == reflect.Pointer {
+			infoPointer = info
+		}
+
+		err = sql.ParseSqlResult(result, infoPointer)
+		if err != nil {
+			return callbackOnError(callbacks, e, err, dbExecutor, outputZero)
+		}
+
+		return callbackOnReturn(callbacks, e, dbExecutor, info)
+	}
+}

+ 31 - 0
infrastructure/database/database.go

@@ -1,6 +1,8 @@
 package database
 
 import (
+	"git.sxidc.com/go-framework/baize/infrastructure/database/data_service"
+	"git.sxidc.com/go-framework/baize/infrastructure/database/operations"
 	"git.sxidc.com/go-framework/baize/infrastructure/database/sql"
 	"git.sxidc.com/go-framework/baize/tag/sql/sql_mapping"
 	"git.sxidc.com/go-tools/utils/reflectutils"
@@ -21,6 +23,35 @@ const (
 	lastUpdatedTimeFieldName = "LastUpdatedTime"
 )
 
+func Transaction(executor Executor, txFunc func(tx Executor) error) error {
+	if executor == nil {
+		return nil
+	}
+
+	if txFunc == nil {
+		return nil
+	}
+
+	switch e := executor.(type) {
+	case *operations.Operations:
+		tx := e.BeginTransaction()
+		err := txFunc(tx)
+		if err != nil {
+			tx.RollbackTransaction()
+			return err
+		}
+		tx.CommitTransaction()
+	case *data_service.DataService:
+		return e.Transaction(func(tx *data_service.Transaction) error {
+			return txFunc(tx)
+		})
+	default:
+		return nil
+	}
+
+	return nil
+}
+
 func InsertEntity(executor Executor, tableName string, e any) error {
 	if executor == nil {
 		return fserr.New("没有传递执行器")

+ 11 - 5
infrastructure/database/operations/operations.go

@@ -105,15 +105,21 @@ func (op *Operations) stopBeatHeart() {
 	}
 }
 
-func (op *Operations) BeginTransaction() *TransactionOperations {
+func (op *Operations) BeginTransaction() *Operations {
 	tx := op.db.Begin()
-	return &TransactionOperations{
-		Operations{
-			db: tx,
-		},
+	return &Operations{
+		db: tx,
 	}
 }
 
+func (op *Operations) RollbackTransaction() {
+	op.db.Rollback()
+}
+
+func (op *Operations) CommitTransaction() {
+	op.db.Commit()
+}
+
 func (op *Operations) AutoMigrate(tables ...Table) error {
 	tx := op.db.Begin()
 

+ 0 - 13
infrastructure/database/operations/transaction.go

@@ -1,13 +0,0 @@
-package operations
-
-type TransactionOperations struct {
-	Operations
-}
-
-func (op *TransactionOperations) RollbackTransaction() {
-	op.db.Rollback()
-}
-
-func (op *TransactionOperations) CommitTransaction() {
-	op.db.Commit()
-}