yjp il y a 1 an
Parent
commit
9cd996e8f8

+ 5 - 8
convenient/entity/service.go

@@ -269,6 +269,10 @@ func GetByID[O any](tableName string, callbacks *Callbacks[O]) binding.ServiceFu
 			Conditions: sql.NewConditions().Equal(entity.ColumnID, e.GetID()),
 		})
 		if err != nil {
+			if database.IsErrorDBRecordNotExist(err) {
+				err = fserr.New(e.DomainCNName() + "不存在")
+			}
+
 			return callbackOnErrorReturn(callbacks, e, err, i, outputZero)
 		}
 
@@ -278,14 +282,7 @@ func GetByID[O any](tableName string, callbacks *Callbacks[O]) binding.ServiceFu
 		}
 
 		info := reflectutils.Zero[O]()
-		var infoPointer any
-
-		infoPointer = &info
-		if reflect.TypeOf(info).Kind() == reflect.Pointer {
-			infoPointer = info
-		}
-
-		err = sql.ParseSqlResult(result, infoPointer)
+		err = sql.ParseSqlResult(result, &info)
 		if err != nil {
 			return callbackOnErrorReturn(callbacks, e, err, i, outputZero)
 		}

+ 6 - 4
convenient/relation/many2many/service.go

@@ -106,6 +106,10 @@ func Update(middleTableName string,
 				TableRowBatch: tableRows,
 			})
 			if err != nil {
+				if database.IsErrorDBRecordHasExist(err) {
+					return fserr.New("关联项已存在")
+				}
+
 				return err
 			}
 
@@ -199,12 +203,10 @@ func Query[TI any](middleTableName string,
 			return errResponse, err
 		}
 
-		output := response.InfosData[TI]{
+		return response.InfosData[TI]{
 			Infos:      infos,
 			TotalCount: totalCount,
 			PageNo:     queryParams.GetPageNo(),
-		}
-
-		return output, nil
+		}, nil
 	}
 }

+ 405 - 21
convenient/relation/one2many/service.go

@@ -1,58 +1,442 @@
 package one2many
 
 import (
-	"encoding/json"
 	"git.sxidc.com/go-framework/baize/convenient/binding"
 	"git.sxidc.com/go-framework/baize/convenient/binding/request"
+	"git.sxidc.com/go-framework/baize/convenient/binding/response"
 	"git.sxidc.com/go-framework/baize/framwork/api"
 	"git.sxidc.com/go-framework/baize/framwork/domain"
+	"git.sxidc.com/go-framework/baize/framwork/domain/entity"
 	"git.sxidc.com/go-framework/baize/framwork/infrastructure"
+	"git.sxidc.com/go-framework/baize/framwork/infrastructure/database"
+	"git.sxidc.com/go-framework/baize/framwork/infrastructure/database/sql"
+	"git.sxidc.com/go-framework/baize/framwork/tag/sql/sql_mapping"
+	"git.sxidc.com/go-tools/utils/reflectutils"
+	"git.sxidc.com/go-tools/utils/slice"
+	"git.sxidc.com/go-tools/utils/strutils"
+	"git.sxidc.com/service-supports/fserr"
+	"reflect"
 )
 
-func UpdateLeft(tableName string) binding.ServiceFunc[any] {
+func UpdateLeft(leftTableName string, leftDomainCNName string, leftRelationFieldName string,
+	rightTableName string, rightRelationColumnName string) binding.ServiceFunc[any] {
 	return func(c *api.Context, params request.Params, objects []domain.Object, i *infrastructure.Infrastructure) (any, error) {
+		object := objects[0]
+		if object == nil {
+			return nil, fserr.New("领域实体为空")
+		}
+
+		dbExecutor := i.DBExecutor()
+
+		leftEntity, ok := object.(entity.Entity)
+		if !ok {
+			return nil, fserr.New("领域对象不是实体")
+		}
+
+		// 字段校验
+		err := leftEntity.CheckFieldID(leftEntity.DomainCNName())
+		if err != nil {
+			return nil, err
+		}
+
+		// left存在性校验
+		leftExist, err := database.CheckExist(dbExecutor, &sql.CheckExistExecuteParams{
+			TableName:  leftTableName,
+			Conditions: sql.NewConditions().Equal(entity.ColumnID, leftEntity.GetID()),
+		})
+		if err != nil {
+			return nil, err
+		}
+
+		if !leftExist {
+			return nil, fserr.New(leftEntity.DomainCNName() + "不存在")
+		}
+
+		if !domain.HasField(object, leftRelationFieldName) {
+			return nil, fserr.New("关联字段" + leftRelationFieldName + "不存在")
+		}
+
+		rightIDs, err := domain.Field[[]string](object, leftRelationFieldName)
+		if err != nil {
+			return nil, err
+		}
+
+		if rightIDs != nil && len(rightIDs) != 0 {
+			for _, rightID := range rightIDs {
+				err := entity.CheckID(leftDomainCNName, leftRelationFieldName, rightID)
+				if err != nil {
+					return nil, err
+				}
+			}
+
+			rightIDs = slice.RemoveRepeatElement(rightIDs)
+		}
+
+		err = database.Transaction(dbExecutor, func(tx database.Executor) error {
+			err := database.Update(tx, &sql.UpdateExecuteParams{
+				TableName:  rightTableName,
+				TableRow:   sql.NewTableRow().Add(rightRelationColumnName, ""),
+				Conditions: sql.NewConditions().Equal(rightRelationColumnName, leftEntity.GetID()),
+			})
+			if err != nil {
+				return err
+			}
+
+			if rightIDs == nil || len(rightIDs) == 0 {
+				return nil
+			}
+
+			rightCount, err := database.Count(dbExecutor, &sql.CountExecuteParams{
+				TableName:  rightTableName,
+				Conditions: sql.NewConditions().In(entity.ColumnID, rightIDs),
+			})
+			if err != nil {
+				return err
+			}
+
+			if int(rightCount) != len(rightIDs) {
+				return fserr.New("部分{{ $toCNName }}不存在")
+			}
+
+			err = database.Update(tx, &sql.UpdateExecuteParams{
+				TableName:  rightTableName,
+				TableRow:   sql.NewTableRow().Add(rightRelationColumnName, leftEntity.GetID()),
+				Conditions: sql.NewConditions().In(entity.ColumnID, rightIDs),
+			})
+			if err != nil {
+				return err
+			}
+
+			return nil
+		})
+		if err != nil {
+			return nil, err
+		}
+
 		return nil, nil
 	}
 }
 
-func QueryLeft[RI any](tableName string) binding.ServiceFunc[RI] {
-	return func(c *api.Context, params request.Params, objects []domain.Object, i *infrastructure.Infrastructure) (RI, error) {
-		var info RI
-		return info, nil
+func QueryLeft[RI any](leftTableName string,
+	rightTableName string, rightRelationColumnName string) binding.ServiceFunc[response.InfosData[RI]] {
+	return func(c *api.Context, params request.Params, objects []domain.Object, i *infrastructure.Infrastructure) (response.InfosData[RI], error) {
+		errResponse := response.InfosData[RI]{
+			Infos: make([]RI, 0),
+		}
+
+		if params == nil {
+			return errResponse, fserr.New("请求参数为空")
+		}
+
+		object := objects[0]
+		if object == nil {
+			return errResponse, fserr.New("领域实体为空")
+		}
+
+		dbExecutor := i.DBExecutor()
+
+		queryParams, ok := params.(request.Query)
+		if !ok {
+			return errResponse, fserr.New("请求参数不是Query接口")
+		}
+
+		leftEntity, ok := object.(entity.Entity)
+		if !ok {
+			return errResponse, fserr.New("领域对象不是实体")
+		}
+
+		// left存在性校验
+		leftExist, err := database.CheckExist(dbExecutor, &sql.CheckExistExecuteParams{
+			TableName:  leftTableName,
+			Conditions: sql.NewConditions().Equal(entity.ColumnID, leftEntity.GetID()),
+		})
+		if err != nil {
+			return errResponse, err
+		}
+
+		if !leftExist {
+			return errResponse, fserr.New(leftEntity.DomainCNName() + "不存在")
+		}
+
+		rightResults, totalCount, err := database.Query(dbExecutor, &sql.QueryExecuteParams{
+			TableName:  rightTableName,
+			Conditions: sql.NewConditions().Equal(rightRelationColumnName, leftEntity.GetID()),
+		})
+		if err != nil && !database.IsErrorDBRecordNotExist(err) {
+			return errResponse, err
+		}
+
+		infos := make([]RI, 0)
+		err = sql.ParseSqlResult(rightResults, &infos)
+		if err != nil {
+			return errResponse, err
+		}
+
+		return response.InfosData[RI]{
+			Infos:      infos,
+			TotalCount: totalCount,
+			PageNo:     queryParams.GetPageNo(),
+		}, nil
 	}
 }
 
-func UpdateRight(tableName string) binding.ServiceFunc[any] {
+func UpdateRight(rightTableName string, rightRelationFieldName string, rightRelationColumnName string,
+	leftTableName string, leftDomainCNName string) binding.ServiceFunc[any] {
 	return func(c *api.Context, params request.Params, objects []domain.Object, i *infrastructure.Infrastructure) (any, error) {
+		object := objects[0]
+		if object == nil {
+			return nil, fserr.New("领域实体为空")
+		}
+
+		dbExecutor := i.DBExecutor()
+
+		rightEntity, ok := object.(entity.Entity)
+		if !ok {
+			return nil, fserr.New("领域对象不是实体")
+		}
+
+		// 字段校验
+		err := rightEntity.CheckFieldID(rightEntity.DomainCNName())
+		if err != nil {
+			return nil, err
+		}
+
+		// right存在性校验
+		rightExist, err := database.CheckExist(dbExecutor, &sql.CheckExistExecuteParams{
+			TableName:  rightTableName,
+			Conditions: sql.NewConditions().Equal(entity.ColumnID, rightEntity.GetID()),
+		})
+		if err != nil {
+			return nil, err
+		}
+
+		if !rightExist {
+			return nil, fserr.New(rightEntity.DomainCNName() + "不存在")
+		}
+
+		if !domain.HasField(object, rightRelationFieldName) {
+			return nil, fserr.New("关联字段" + rightRelationFieldName + "不存在")
+		}
+
+		leftID, err := domain.Field[string](object, rightRelationFieldName)
+		if err != nil {
+			return nil, err
+		}
+
+		if strutils.IsStringNotEmpty(leftID) {
+			leftExist, err := database.CheckExist(dbExecutor, &sql.CheckExistExecuteParams{
+				TableName:  leftTableName,
+				Conditions: sql.NewConditions().Equal(entity.ColumnID, leftID),
+			})
+			if err != nil {
+				return nil, err
+			}
+
+			if !leftExist {
+				return nil, fserr.New(leftDomainCNName + "不存在")
+			}
+		}
+
+		err = database.Update(dbExecutor, &sql.UpdateExecuteParams{
+			TableName:  rightTableName,
+			TableRow:   sql.NewTableRow().Add(rightRelationColumnName, leftID),
+			Conditions: sql.NewConditions().Equal(entity.ColumnID, rightEntity.GetID()),
+		})
+		if err != nil {
+			return nil, err
+		}
+
 		return nil, nil
 	}
 }
 
-func QueryRight[LI any](tableName string) binding.ServiceFunc[LI] {
+func QueryRight[LI any](rightTableName string, rightRelationFieldName string, leftTableName string) binding.ServiceFunc[LI] {
 	return func(c *api.Context, params request.Params, objects []domain.Object, i *infrastructure.Infrastructure) (LI, error) {
-		var info LI
-		return info, nil
+		outputZero := reflectutils.Zero[LI]()
+
+		dbExecutor := i.DBExecutor()
+
+		object := objects[0]
+		if object == nil {
+			return outputZero, fserr.New("领域实体为空")
+		}
+
+		rightEntity, ok := object.(entity.Entity)
+		if !ok {
+			return outputZero, fserr.New("领域对象不是实体")
+		}
+
+		// right存在性校验
+		rightExist, err := database.CheckExist(dbExecutor, &sql.CheckExistExecuteParams{
+			TableName:  rightTableName,
+			Conditions: sql.NewConditions().Equal(entity.ColumnID, rightEntity.GetID()),
+		})
+		if err != nil {
+			return outputZero, err
+		}
+
+		if !rightExist {
+			return outputZero, fserr.New(rightEntity.DomainCNName() + "不存在")
+		}
+
+		if !domain.HasField(object, rightRelationFieldName) {
+			return outputZero, fserr.New("关联字段" + rightRelationFieldName + "不存在")
+		}
+
+		leftID, err := domain.Field[string](object, rightRelationFieldName)
+		if err != nil {
+			return outputZero, err
+		}
+
+		leftResult, err := database.QueryOne(dbExecutor, &sql.QueryOneExecuteParams{
+			TableName:  leftTableName,
+			Conditions: sql.NewConditions().Equal(entity.ColumnID, leftID),
+		})
+		if err != nil && !database.IsErrorDBRecordNotExist(err) {
+			return outputZero, err
+		}
+
+		leftInfo := reflectutils.Zero[LI]()
+		err = sql.ParseSqlResult(leftResult, &leftInfo)
+		if err != nil {
+			return outputZero, err
+		}
+
+		return leftInfo, nil
 	}
 }
 
-func QueryRightWithLeftInfo[RI any, LI any](tableName string) binding.ServiceFunc[map[string]any] {
+func QueryRightWithLeftInfo[RI any, LI any](rightTableName string, leftTableName string) binding.ServiceFunc[map[string]any] {
 	return func(c *api.Context, params request.Params, objects []domain.Object, i *infrastructure.Infrastructure) (map[string]any, error) {
-		info := new(struct {
-			Self RI `json:"self"`
-			With LI `json:"with"`
-		})
+		errResponse := response.InfosData[map[string]any]{
+			Infos: make([]map[string]any, 0),
+		}
+
+		if params == nil {
+			return errResponse, fserr.New("请求参数为空")
+		}
+
+		object := objects[0]
+		if object == nil {
+			return errResponse, fserr.New("领域实体为空")
+		}
+
+		dbExecutor := i.DBExecutor()
+
+		queryParams, ok := params.(request.Query)
+		if !ok {
+			return errResponse, fserr.New("请求参数不是Query接口")
+		}
+
+		fromEntity, ok := object.(entity.Entity)
+		if !ok {
+			return errResponse, fserr.New("领域对象不是实体")
+		}
 
-		infoJson, err := json.Marshal(info)
+		conditions := sql.NewConditions()
+
+		fromFields, err := sql_mapping.DefaultUsage(fromEntity)
 		if err != nil {
-			return nil, err
+			return errResponse, err
+		}
+
+		for _, fromField := range fromFields {
+			hasDeal := false
+			if fromFieldCallback != nil {
+				hasDeal = fromFieldCallback(conditions, fromField.FieldName, fromField.ColumnName, fromField.Value)
+			}
+
+			if !hasDeal {
+				fieldValue := reflect.ValueOf(fromField.Value)
+				if !fieldValue.IsZero() {
+					conditions.Equal(fromField.ColumnName, fromField.Value)
+				}
+			}
+		}
+
+		fromResults, totalCount, err := database.Query(dbExecutor, &sql.QueryExecuteParams{
+			TableName:  fromTableName,
+			Conditions: conditions,
+			PageNo:     queryParams.GetPageNo(),
+			PageSize:   queryParams.GetPageSize(),
+		})
+		if err != nil {
+			return errResponse, nil
+		}
+
+		if fromResults == nil || len(fromResults) == 0 {
+			return response.InfosData[map[string]any]{
+				Infos:      make([]map[string]any, 0),
+				TotalCount: 0,
+				PageNo:     0,
+			}, nil
 		}
 
-		retMap := make(map[string]any)
-		err = json.Unmarshal(infoJson, &retMap)
+		toIDs := make([]string, 0)
+		for _, fromResult := range fromResults {
+			toID := fromResult.ColumnValueString(fromRelationColumnName)
+			if strutils.IsStringNotEmpty(toID) {
+				toIDs = append(toIDs, toID)
+			}
+		}
+
+		toResults, _, err := database.Query(dbExecutor, &sql.QueryExecuteParams{
+			TableName:  toTableName,
+			Conditions: sql.NewConditions().In(entity.ColumnID, toIDs),
+		})
 		if err != nil {
-			return nil, err
+			return errResponse, err
+		}
+
+		toResultMap := make(map[string]sql.Result)
+		for _, toResult := range toResults {
+			toID := toResult.ColumnValueString(entity.ColumnID)
+			toResultMap[toID] = toResult
+		}
+
+		infos := make([]map[string]any, len(fromResults))
+		for index, fromResult := range fromResults {
+			fromInfo := reflectutils.Zero[FI]()
+			toInfo := reflectutils.Zero[FI]()
+
+			err = sql.ParseSqlResult(fromResult, &fromInfo)
+			if err != nil {
+				return errResponse, err
+			}
+
+			toID := fromResult.ColumnValueString(fromRelationColumnName)
+			if strutils.IsStringEmpty(toID) {
+				infos[index] = map[string]any{
+					"self": fromInfo,
+					"with": toInfo,
+				}
+				continue
+			}
+
+			toResult, ok := toResultMap[toID]
+			if !ok {
+				infos[index] = map[string]any{
+					"self": fromInfo,
+					"with": toInfo,
+				}
+				continue
+			}
+
+			err = sql.ParseSqlResult(toResult, &toInfo)
+			if err != nil {
+				return errResponse, err
+			}
+
+			infos[index] = map[string]any{
+				"self": fromInfo,
+				"with": toInfo,
+			}
 		}
 
-		return retMap, nil
+		return response.InfosData[map[string]any]{
+			Infos:      infos,
+			TotalCount: totalCount,
+			PageNo:     queryParams.GetPageNo(),
+		}, nil
 	}
 }

+ 13 - 1
convenient/relation/one2many/simple.go

@@ -1,9 +1,11 @@
 package one2many
 
 import (
+	"fmt"
 	"git.sxidc.com/go-framework/baize/convenient/binding"
 	"git.sxidc.com/go-framework/baize/convenient/binding/request"
 	"git.sxidc.com/go-framework/baize/framwork/domain/entity"
+	"github.com/iancoleman/strcase"
 )
 
 // Simple 关联的Bind参数
@@ -39,8 +41,18 @@ type Simple[LI any, RI any] struct {
 }
 
 func (simple *Simple[LI, RI]) bind(binder *binding.Binder) {
-	//options := simple.options
+	options := simple.options
 
+	leftDomainPath := entity.RelativeDomainPath(simple.Left)
+	rightDomainPath := entity.RelativeDomainPath(simple.Right)
+
+	leftRelationFieldName := fmt.Sprintf("%sID", simple.Right.DomainCamelName())
+	rightRelationFieldName := fmt.Sprintf("%sID", simple.Left.DomainCamelName())
+
+	leftTableName := entity.TableName(simple.Schema, simple.Left)
+	leftRelationColumnName := fmt.Sprintf("%s_id", strcase.ToSnake(simple.Right.DomainCamelName()))
+	rightTableName := entity.TableName(simple.Schema, simple.Right)
+	rightRelationColumnName := fmt.Sprintf("%s_id", strcase.ToSnake(simple.Left.DomainCamelName()))
 }
 
 func BindSimple[LI any, RI any](binder *binding.Binder, simple *Simple[LI, RI], opts ...Option) {

+ 113 - 72
convenient/relation/one2one/service.go

@@ -3,19 +3,22 @@ package one2one
 import (
 	"git.sxidc.com/go-framework/baize/convenient/binding"
 	"git.sxidc.com/go-framework/baize/convenient/binding/request"
+	"git.sxidc.com/go-framework/baize/convenient/binding/response"
 	"git.sxidc.com/go-framework/baize/framwork/api"
 	"git.sxidc.com/go-framework/baize/framwork/domain"
 	"git.sxidc.com/go-framework/baize/framwork/domain/entity"
 	"git.sxidc.com/go-framework/baize/framwork/infrastructure"
 	"git.sxidc.com/go-framework/baize/framwork/infrastructure/database"
 	"git.sxidc.com/go-framework/baize/framwork/infrastructure/database/sql"
+	"git.sxidc.com/go-framework/baize/framwork/tag/sql/sql_mapping"
 	"git.sxidc.com/go-tools/utils/reflectutils"
 	"git.sxidc.com/go-tools/utils/strutils"
 	"git.sxidc.com/service-supports/fserr"
 	"reflect"
 )
 
-func Update(fromTableName string, fromRelationFieldName string, fromRelationColumnName string, toTableName string, toDomainCNName string, toRelationColumnName string) binding.ServiceFunc[any] {
+func Update(fromTableName string, fromRelationFieldName string, fromRelationColumnName string,
+	toTableName string, toDomainCNName string, toRelationColumnName string) binding.ServiceFunc[any] {
 	return func(c *api.Context, params request.Params, objects []domain.Object, i *infrastructure.Infrastructure) (any, error) {
 		object := objects[0]
 		if object == nil {
@@ -131,56 +134,41 @@ func Query[TI any](fromTableName string, toTableName string, toRelationColumnNam
 	return func(c *api.Context, params request.Params, objects []domain.Object, i *infrastructure.Infrastructure) (TI, error) {
 		outputZero := reflectutils.Zero[TI]()
 
-		dbExecutor := i.DBExecutor()
-
 		object := objects[0]
 		if object == nil {
 			return outputZero, fserr.New("领域实体为空")
 		}
 
+		dbExecutor := i.DBExecutor()
+
 		fromEntity, ok := object.(entity.Entity)
 		if !ok {
 			return outputZero, fserr.New("领域对象不是实体")
 		}
 
 		// from存在性校验
-		fromResult, err := database.QueryOne(dbExecutor, &sql.QueryOneExecuteParams{
+		fromExist, err := database.CheckExist(dbExecutor, &sql.CheckExistExecuteParams{
 			TableName:  fromTableName,
 			Conditions: sql.NewConditions().Equal(entity.ColumnID, fromEntity.GetID()),
 		})
 		if err != nil {
-			if database.IsErrorDBRecordNotExist(err) {
-				return outputZero, fserr.New(fromEntity.DomainCNName() + "不存在")
-			}
-
 			return outputZero, err
 		}
 
-		existFrom := reflect.New(reflect.TypeOf(object).Elem()).Interface()
-		err = sql.ParseSqlResult(fromResult, existFrom)
-		if err != nil {
-			return outputZero, err
+		if !fromExist {
+			return outputZero, fserr.New(fromEntity.DomainCNName() + "不存在")
 		}
 
-		existFromEntity := existFrom.(entity.Entity)
-
 		toResult, err := database.QueryOne(dbExecutor, &sql.QueryOneExecuteParams{
 			TableName:  toTableName,
-			Conditions: sql.NewConditions().Equal(toRelationColumnName, existFromEntity.GetID()),
+			Conditions: sql.NewConditions().Equal(toRelationColumnName, fromEntity.GetID()),
 		})
-		if err != nil {
+		if err != nil && !database.IsErrorDBRecordNotExist(err) {
 			return outputZero, err
 		}
 
 		info := reflectutils.Zero[TI]()
-		var infoPointer any
-
-		infoPointer = &info
-		if reflect.TypeOf(info).Kind() == reflect.Pointer {
-			infoPointer = info
-		}
-
-		err = sql.ParseSqlResult(toResult, infoPointer)
+		err = sql.ParseSqlResult(toResult, &info)
 		if err != nil {
 			return outputZero, err
 		}
@@ -189,86 +177,139 @@ func Query[TI any](fromTableName string, toTableName string, toRelationColumnNam
 	}
 }
 
-func QueryWithOtherInfo[FI any, TI any](fromTableName string, toTableName string, toRelationColumnName string) binding.ServiceFunc[map[string]any] {
-	return func(c *api.Context, params request.Params, objects []domain.Object, i *infrastructure.Infrastructure) (map[string]any, error) {
-		outputFromZero := reflectutils.Zero[FI]()
-		outputToZero := reflectutils.Zero[TI]()
+type ConditionFieldCallback func(conditions *sql.Conditions, fieldName string, columnName string, value any) (hasDeal bool)
 
-		zeroRetMap := map[string]any{
-			"self": outputFromZero,
-			"with": outputToZero,
+func QueryWithOtherInfo[FI any, TI any](fromTableName string, fromRelationColumnName string, fromFieldCallback ConditionFieldCallback, toTableName string) binding.ServiceFunc[response.InfosData[map[string]any]] {
+	return func(c *api.Context, params request.Params, objects []domain.Object, i *infrastructure.Infrastructure) (response.InfosData[map[string]any], error) {
+		errResponse := response.InfosData[map[string]any]{
+			Infos: make([]map[string]any, 0),
 		}
 
-		dbExecutor := i.DBExecutor()
+		if params == nil {
+			return errResponse, fserr.New("请求参数为空")
+		}
 
 		object := objects[0]
 		if object == nil {
-			return zeroRetMap, fserr.New("领域实体为空")
+			return errResponse, fserr.New("领域实体为空")
+		}
+
+		dbExecutor := i.DBExecutor()
+
+		queryParams, ok := params.(request.Query)
+		if !ok {
+			return errResponse, fserr.New("请求参数不是Query接口")
 		}
 
 		fromEntity, ok := object.(entity.Entity)
 		if !ok {
-			return zeroRetMap, fserr.New("领域对象不是实体")
+			return errResponse, fserr.New("领域对象不是实体")
 		}
 
-		// from存在性校验
-		fromResult, err := database.QueryOne(dbExecutor, &sql.QueryOneExecuteParams{
-			TableName:  fromTableName,
-			Conditions: sql.NewConditions().Equal(entity.ColumnID, fromEntity.GetID()),
-		})
+		conditions := sql.NewConditions()
+
+		fromFields, err := sql_mapping.DefaultUsage(fromEntity)
 		if err != nil {
-			if database.IsErrorDBRecordNotExist(err) {
-				return zeroRetMap, fserr.New(fromEntity.DomainCNName() + "不存在")
+			return errResponse, err
+		}
+
+		for _, fromField := range fromFields {
+			hasDeal := false
+			if fromFieldCallback != nil {
+				hasDeal = fromFieldCallback(conditions, fromField.FieldName, fromField.ColumnName, fromField.Value)
 			}
 
-			return zeroRetMap, err
+			if !hasDeal {
+				fieldValue := reflect.ValueOf(fromField.Value)
+				if !fieldValue.IsZero() {
+					conditions.Equal(fromField.ColumnName, fromField.Value)
+				}
+			}
 		}
 
-		existFrom := reflect.New(reflect.TypeOf(object).Elem()).Interface()
-		err = sql.ParseSqlResult(fromResult, existFrom)
+		fromResults, totalCount, err := database.Query(dbExecutor, &sql.QueryExecuteParams{
+			TableName:  fromTableName,
+			Conditions: conditions,
+			PageNo:     queryParams.GetPageNo(),
+			PageSize:   queryParams.GetPageSize(),
+		})
 		if err != nil {
-			return zeroRetMap, err
+			return errResponse, nil
 		}
 
-		existFromEntity := existFrom.(entity.Entity)
+		if fromResults == nil || len(fromResults) == 0 {
+			return response.InfosData[map[string]any]{
+				Infos:      make([]map[string]any, 0),
+				TotalCount: 0,
+				PageNo:     0,
+			}, nil
+		}
 
-		toResult, err := database.QueryOne(dbExecutor, &sql.QueryOneExecuteParams{
+		toIDs := make([]string, 0)
+		for _, fromResult := range fromResults {
+			toID := fromResult.ColumnValueString(fromRelationColumnName)
+			if strutils.IsStringNotEmpty(toID) {
+				toIDs = append(toIDs, toID)
+			}
+		}
+
+		toResults, _, err := database.Query(dbExecutor, &sql.QueryExecuteParams{
 			TableName:  toTableName,
-			Conditions: sql.NewConditions().Equal(toRelationColumnName, existFromEntity.GetID()),
+			Conditions: sql.NewConditions().In(entity.ColumnID, toIDs),
 		})
-		if err != nil && !database.IsErrorDBRecordNotExist(err) {
-			return zeroRetMap, err
+		if err != nil {
+			return errResponse, err
 		}
 
-		fromInfo := reflectutils.Zero[FI]()
-		var fromInfoPointer any
-
-		fromInfoPointer = &fromInfo
-		if reflect.TypeOf(fromInfo).Kind() == reflect.Pointer {
-			fromInfoPointer = fromInfo
+		toResultMap := make(map[string]sql.Result)
+		for _, toResult := range toResults {
+			toID := toResult.ColumnValueString(entity.ColumnID)
+			toResultMap[toID] = toResult
 		}
 
-		err = sql.ParseSqlResult(fromResult, fromInfoPointer)
-		if err != nil {
-			return zeroRetMap, err
-		}
+		infos := make([]map[string]any, len(fromResults))
+		for index, fromResult := range fromResults {
+			fromInfo := reflectutils.Zero[FI]()
+			toInfo := reflectutils.Zero[TI]()
 
-		toInfo := reflectutils.Zero[FI]()
-		var toInfoPointer any
+			err = sql.ParseSqlResult(fromResult, &fromInfo)
+			if err != nil {
+				return errResponse, err
+			}
 
-		toInfoPointer = &toInfo
-		if reflect.TypeOf(toInfo).Kind() == reflect.Pointer {
-			toInfoPointer = toInfo
-		}
+			toID := fromResult.ColumnValueString(fromRelationColumnName)
+			if strutils.IsStringEmpty(toID) {
+				infos[index] = map[string]any{
+					"self": fromInfo,
+					"with": toInfo,
+				}
+				continue
+			}
 
-		err = sql.ParseSqlResult(toResult, toInfoPointer)
-		if err != nil {
-			return zeroRetMap, err
+			toResult, ok := toResultMap[toID]
+			if !ok {
+				infos[index] = map[string]any{
+					"self": fromInfo,
+					"with": toInfo,
+				}
+				continue
+			}
+
+			err = sql.ParseSqlResult(toResult, &toInfo)
+			if err != nil {
+				return errResponse, err
+			}
+
+			infos[index] = map[string]any{
+				"self": fromInfo,
+				"with": toInfo,
+			}
 		}
 
-		return map[string]any{
-			"self": fromInfo,
-			"with": toInfo,
+		return response.InfosData[map[string]any]{
+			Infos:      infos,
+			TotalCount: totalCount,
+			PageNo:     queryParams.GetPageNo(),
 		}, nil
 	}
 }

+ 12 - 6
convenient/relation/one2one/simple.go

@@ -85,12 +85,12 @@ func (simple *Simple[LI, RI]) bind(binder *binding.Binder) {
 
 		if !options.disableLeftWithRightQuery {
 			// 左到右查询,携带右方信息
-			binding.GetBind(binder, &binding.SimpleBindItem[map[string]any]{
+			binding.GetBind(binder, &binding.SimpleBindItem[response.InfosData[map[string]any]]{
 				Path:          leftDomainPath + rightDomainPath + "/queryWith",
-				ResponseFunc:  response.SendMapResponse,
+				ResponseFunc:  response.SendInfosResponse[map[string]any],
 				RequestParams: simple.LeftQueryWithRightQueryParams,
 				Objects:       []domain.Object{simple.Left},
-				ServiceFunc:   QueryWithOtherInfo[LI, RI](leftTableName, rightTableName, rightRelationColumnName),
+				ServiceFunc:   QueryWithOtherInfo[LI, RI](leftTableName, leftRelationColumnName, options.leftQueryWithConditionFieldCallback, rightTableName),
 			})
 		}
 	}
@@ -121,12 +121,12 @@ func (simple *Simple[LI, RI]) bind(binder *binding.Binder) {
 
 		if !options.disableRightWithLeftQuery {
 			// 右到左查询,携带左方信息
-			binding.GetBind(binder, &binding.SimpleBindItem[map[string]any]{
+			binding.GetBind(binder, &binding.SimpleBindItem[response.InfosData[map[string]any]]{
 				Path:          rightDomainPath + leftDomainPath + "/queryWith",
-				ResponseFunc:  response.SendMapResponse,
+				ResponseFunc:  response.SendInfosResponse[map[string]any],
 				RequestParams: simple.RightQueryWithLeftQueryParams,
 				Objects:       []domain.Object{simple.Right},
-				ServiceFunc:   QueryWithOtherInfo[RI, LI](rightTableName, leftTableName, leftRelationColumnName),
+				ServiceFunc:   QueryWithOtherInfo[RI, LI](rightTableName, rightRelationColumnName, options.rightQueryWithConditionFieldCallback, leftTableName),
 			})
 		}
 	}
@@ -170,6 +170,12 @@ type Options struct {
 
 	// 关闭右实体带左实体信息查询
 	disableRightWithLeftQuery bool
+
+	// 左查询条件构造回调
+	leftQueryWithConditionFieldCallback ConditionFieldCallback
+
+	// 右查询条件构造回调
+	rightQueryWithConditionFieldCallback ConditionFieldCallback
 }
 
 func WithDisableLeft() Option {

+ 4 - 0
convenient/relation/remote/service.go

@@ -110,6 +110,10 @@ func Update(middleTableName string,
 				TableRowBatch: tableRows,
 			})
 			if err != nil {
+				if database.IsErrorDBRecordHasExist(err) {
+					return fserr.New("关联项已存在")
+				}
+
 				return err
 			}
 

+ 10 - 0
convenient/value_object/service.go

@@ -183,6 +183,11 @@ func Query[O any](tableName string, callbacks *Callbacks[response.InfosData[O]],
 
 func CreateTx(tableName string, callbacks *Callbacks[any]) binding.ServiceFunc[any] {
 	return func(c *api.Context, params request.Params, objects []domain.Object, i *infrastructure.Infrastructure) (any, error) {
+		object := objects[0]
+		if object == nil {
+			return nil, fserr.New("领域实体为空")
+		}
+
 		dbExecutor := i.DBExecutor()
 
 		valueObject, ok := objects[0].(value_object.ValueObject)
@@ -222,6 +227,11 @@ func CreateTx(tableName string, callbacks *Callbacks[any]) binding.ServiceFunc[a
 
 func DeleteTx(tableName string, callbacks *Callbacks[any]) binding.ServiceFunc[any] {
 	return func(c *api.Context, params request.Params, objects []domain.Object, i *infrastructure.Infrastructure) (any, error) {
+		object := objects[0]
+		if object == nil {
+			return nil, fserr.New("领域实体为空")
+		}
+
 		dbExecutor := i.DBExecutor()
 
 		valueObject, ok := objects[0].(value_object.ValueObject)