实现修改批次绑定的猪栏
This commit is contained in:
68
docs/docs.go
68
docs/docs.go
@@ -1085,6 +1085,71 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/api/v1/pig-batches/{id}/pens": {
|
||||||
|
"put": {
|
||||||
|
"description": "更新指定猪批次当前关联的猪栏列表",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"猪批次管理"
|
||||||
|
],
|
||||||
|
"summary": "更新猪批次关联的猪栏",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "猪批次ID",
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "猪批次关联的猪栏ID列表",
|
||||||
|
"name": "body",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/dto.PigBatchUpdatePensRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "更新成功",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/controller.Response"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "请求参数错误或无效的ID格式",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/controller.Response"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "猪批次或猪栏不存在",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/controller.Response"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"409": {
|
||||||
|
"description": "业务逻辑冲突 (如猪栏已被占用)",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/controller.Response"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "内部服务器错误",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/controller.Response"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/api/v1/pig-houses": {
|
"/api/v1/pig-houses": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "获取所有猪舍的列表",
|
"description": "获取所有猪舍的列表",
|
||||||
@@ -2280,6 +2345,9 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"dto.PigBatchUpdatePensRequest": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
"dto.PigHouseResponse": {
|
"dto.PigHouseResponse": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|||||||
@@ -1074,6 +1074,71 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/api/v1/pig-batches/{id}/pens": {
|
||||||
|
"put": {
|
||||||
|
"description": "更新指定猪批次当前关联的猪栏列表",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"猪批次管理"
|
||||||
|
],
|
||||||
|
"summary": "更新猪批次关联的猪栏",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "猪批次ID",
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "猪批次关联的猪栏ID列表",
|
||||||
|
"name": "body",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/dto.PigBatchUpdatePensRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "更新成功",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/controller.Response"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "请求参数错误或无效的ID格式",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/controller.Response"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "猪批次或猪栏不存在",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/controller.Response"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"409": {
|
||||||
|
"description": "业务逻辑冲突 (如猪栏已被占用)",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/controller.Response"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "内部服务器错误",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/controller.Response"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/api/v1/pig-houses": {
|
"/api/v1/pig-houses": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "获取所有猪舍的列表",
|
"description": "获取所有猪舍的列表",
|
||||||
@@ -2269,6 +2334,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"dto.PigBatchUpdatePensRequest": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
"dto.PigHouseResponse": {
|
"dto.PigHouseResponse": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|||||||
@@ -401,6 +401,8 @@ definitions:
|
|||||||
- $ref: '#/definitions/models.PigBatchStatus'
|
- $ref: '#/definitions/models.PigBatchStatus'
|
||||||
description: 批次状态,可选
|
description: 批次状态,可选
|
||||||
type: object
|
type: object
|
||||||
|
dto.PigBatchUpdatePensRequest:
|
||||||
|
type: object
|
||||||
dto.PigHouseResponse:
|
dto.PigHouseResponse:
|
||||||
properties:
|
properties:
|
||||||
description:
|
description:
|
||||||
@@ -1438,6 +1440,49 @@ paths:
|
|||||||
summary: 更新猪批次
|
summary: 更新猪批次
|
||||||
tags:
|
tags:
|
||||||
- 猪批次管理
|
- 猪批次管理
|
||||||
|
/api/v1/pig-batches/{id}/pens:
|
||||||
|
put:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: 更新指定猪批次当前关联的猪栏列表
|
||||||
|
parameters:
|
||||||
|
- description: 猪批次ID
|
||||||
|
in: path
|
||||||
|
name: id
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
|
- description: 猪批次关联的猪栏ID列表
|
||||||
|
in: body
|
||||||
|
name: body
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/dto.PigBatchUpdatePensRequest'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: 更新成功
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/controller.Response'
|
||||||
|
"400":
|
||||||
|
description: 请求参数错误或无效的ID格式
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/controller.Response'
|
||||||
|
"404":
|
||||||
|
description: 猪批次或猪栏不存在
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/controller.Response'
|
||||||
|
"409":
|
||||||
|
description: 业务逻辑冲突 (如猪栏已被占用)
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/controller.Response'
|
||||||
|
"500":
|
||||||
|
description: 内部服务器错误
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/controller.Response'
|
||||||
|
summary: 更新猪批次关联的猪栏
|
||||||
|
tags:
|
||||||
|
- 猪批次管理
|
||||||
/api/v1/pig-houses:
|
/api/v1/pig-houses:
|
||||||
get:
|
get:
|
||||||
description: 获取所有猪舍的列表
|
description: 获取所有猪舍的列表
|
||||||
|
|||||||
@@ -233,6 +233,7 @@ func (a *API) setupRoutes() {
|
|||||||
pigBatchGroup.GET("/:id", a.pigBatchController.GetPigBatch)
|
pigBatchGroup.GET("/:id", a.pigBatchController.GetPigBatch)
|
||||||
pigBatchGroup.PUT("/:id", a.pigBatchController.UpdatePigBatch)
|
pigBatchGroup.PUT("/:id", a.pigBatchController.UpdatePigBatch)
|
||||||
pigBatchGroup.DELETE("/:id", a.pigBatchController.DeletePigBatch)
|
pigBatchGroup.DELETE("/:id", a.pigBatchController.DeletePigBatch)
|
||||||
|
pigBatchGroup.PUT("/:id/pens", a.pigBatchController.UpdatePigBatchPens)
|
||||||
}
|
}
|
||||||
a.logger.Info("猪批次相关接口注册成功 (需要认证和审计)")
|
a.logger.Info("猪批次相关接口注册成功 (需要认证和审计)")
|
||||||
|
|
||||||
|
|||||||
@@ -188,3 +188,48 @@ func (c *PigBatchController) ListPigBatches(ctx *gin.Context) {
|
|||||||
|
|
||||||
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取成功", respDTOs, action, "获取成功", respDTOs)
|
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取成功", respDTOs, action, "获取成功", respDTOs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdatePigBatchPens godoc
|
||||||
|
// @Summary 更新猪批次关联的猪栏
|
||||||
|
// @Description 更新指定猪批次当前关联的猪栏列表
|
||||||
|
// @Tags 猪批次管理
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "猪批次ID"
|
||||||
|
// @Param body body dto.PigBatchUpdatePensRequest true "猪批次关联的猪栏ID列表"
|
||||||
|
// @Success 200 {object} controller.Response "更新成功"
|
||||||
|
// @Failure 400 {object} controller.Response "请求参数错误或无效的ID格式"
|
||||||
|
// @Failure 404 {object} controller.Response "猪批次或猪栏不存在"
|
||||||
|
// @Failure 409 {object} controller.Response "业务逻辑冲突 (如猪栏已被占用)"
|
||||||
|
// @Failure 500 {object} controller.Response "内部服务器错误"
|
||||||
|
// @Router /api/v1/pig-batches/{id}/pens [put]
|
||||||
|
func (c *PigBatchController) UpdatePigBatchPens(ctx *gin.Context) {
|
||||||
|
const action = "更新猪批次关联猪栏"
|
||||||
|
batchID, err := strconv.ParseUint(ctx.Param("id"), 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的猪批次ID格式", action, "ID格式错误", ctx.Param("id"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var req dto.PigBatchUpdatePensRequest
|
||||||
|
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||||
|
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", req)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.service.UpdatePigBatchPens(uint(batchID), req.PenIDs)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, service.ErrPigBatchNotFound) || errors.Is(err, service.ErrPenNotFound) {
|
||||||
|
controller.SendErrorWithAudit(ctx, controller.CodeNotFound, err.Error(), action, err.Error(), batchID)
|
||||||
|
return
|
||||||
|
} else if errors.Is(err, service.ErrPigBatchNotActive) || errors.Is(err, service.ErrPenOccupiedByOtherBatch) || errors.Is(err, service.ErrPenStatusInvalidForAllocation) || errors.Is(err, service.ErrPenNotAssociatedWithBatch) {
|
||||||
|
controller.SendErrorWithAudit(ctx, controller.CodeConflict, err.Error(), action, err.Error(), batchID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.logger.Errorf("%s: 业务逻辑失败: %v", action, err)
|
||||||
|
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新猪批次关联猪栏失败", action, err.Error(), batchID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "更新成功", nil, action, "更新成功", batchID)
|
||||||
|
}
|
||||||
|
|||||||
@@ -229,7 +229,7 @@ func (c *PigFarmController) CreatePen(ctx *gin.Context) {
|
|||||||
HouseID: pen.HouseID,
|
HouseID: pen.HouseID,
|
||||||
Capacity: pen.Capacity,
|
Capacity: pen.Capacity,
|
||||||
Status: pen.Status,
|
Status: pen.Status,
|
||||||
PigBatchID: pen.PigBatchID,
|
PigBatchID: *pen.PigBatchID,
|
||||||
}
|
}
|
||||||
controller.SendSuccessWithAudit(ctx, controller.CodeCreated, "创建成功", resp, action, "创建成功", resp)
|
controller.SendSuccessWithAudit(ctx, controller.CodeCreated, "创建成功", resp, action, "创建成功", resp)
|
||||||
}
|
}
|
||||||
@@ -267,7 +267,7 @@ func (c *PigFarmController) GetPen(ctx *gin.Context) {
|
|||||||
HouseID: pen.HouseID,
|
HouseID: pen.HouseID,
|
||||||
Capacity: pen.Capacity,
|
Capacity: pen.Capacity,
|
||||||
Status: pen.Status,
|
Status: pen.Status,
|
||||||
PigBatchID: pen.PigBatchID,
|
PigBatchID: *pen.PigBatchID,
|
||||||
}
|
}
|
||||||
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取成功", resp, action, "获取成功", resp)
|
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取成功", resp, action, "获取成功", resp)
|
||||||
}
|
}
|
||||||
@@ -296,7 +296,7 @@ func (c *PigFarmController) ListPens(ctx *gin.Context) {
|
|||||||
HouseID: pen.HouseID,
|
HouseID: pen.HouseID,
|
||||||
Capacity: pen.Capacity,
|
Capacity: pen.Capacity,
|
||||||
Status: pen.Status,
|
Status: pen.Status,
|
||||||
PigBatchID: pen.PigBatchID,
|
PigBatchID: *pen.PigBatchID,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -344,7 +344,7 @@ func (c *PigFarmController) UpdatePen(ctx *gin.Context) {
|
|||||||
HouseID: pen.HouseID,
|
HouseID: pen.HouseID,
|
||||||
Capacity: pen.Capacity,
|
Capacity: pen.Capacity,
|
||||||
Status: pen.Status,
|
Status: pen.Status,
|
||||||
PigBatchID: pen.PigBatchID,
|
PigBatchID: *pen.PigBatchID,
|
||||||
}
|
}
|
||||||
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "更新成功", resp, action, "更新成功", resp)
|
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "更新成功", resp, action, "更新成功", resp)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package dto
|
|||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.huangwc.com/pig/pig-farm-controller/internal/infra/models" // 导入 models 包以使用 PigBatchOriginType 和 PigBatchStatus
|
"git.huangwc.com/pig/pig-farm-controller/internal/infra/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PigBatchCreateDTO 定义了创建猪批次的请求结构
|
// PigBatchCreateDTO 定义了创建猪批次的请求结构
|
||||||
@@ -43,3 +43,8 @@ type PigBatchResponseDTO struct {
|
|||||||
CreateTime time.Time `json:"create_time"` // 创建时间
|
CreateTime time.Time `json:"create_time"` // 创建时间
|
||||||
UpdateTime time.Time `json:"update_time"` // 更新时间
|
UpdateTime time.Time `json:"update_time"` // 更新时间
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PigBatchUpdatePensRequest 用于更新猪批次关联猪栏的请求体
|
||||||
|
type PigBatchUpdatePensRequest struct {
|
||||||
|
PenIDs []uint `json:"penIDs" binding:"required,min=0" example:"[1,2,3]"`
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"git.huangwc.com/pig/pig-farm-controller/internal/app/dto"
|
"git.huangwc.com/pig/pig-farm-controller/internal/app/dto"
|
||||||
"git.huangwc.com/pig/pig-farm-controller/internal/infra/logs"
|
"git.huangwc.com/pig/pig-farm-controller/internal/infra/logs"
|
||||||
@@ -13,7 +14,12 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
ErrPigBatchNotFound = errors.New("指定的猪批次不存在")
|
ErrPigBatchNotFound = errors.New("指定的猪批次不存在")
|
||||||
ErrPigBatchActive = errors.New("活跃的猪批次不能被删除") // 新增错误:活跃的猪批次不能被删除
|
ErrPigBatchActive = errors.New("活跃的猪批次不能被删除")
|
||||||
|
ErrPigBatchNotActive = errors.New("猪批次不处于活跃状态,无法修改关联猪栏")
|
||||||
|
ErrPenNotFound = errors.New("指定的猪栏不存在")
|
||||||
|
ErrPenOccupiedByOtherBatch = errors.New("猪栏已被其他批次占用")
|
||||||
|
ErrPenStatusInvalidForAllocation = errors.New("猪栏状态不允许分配")
|
||||||
|
ErrPenNotAssociatedWithBatch = errors.New("猪栏未与该批次关联")
|
||||||
)
|
)
|
||||||
|
|
||||||
// PigBatchService 提供了猪批次管理的业务逻辑
|
// PigBatchService 提供了猪批次管理的业务逻辑
|
||||||
@@ -23,18 +29,24 @@ type PigBatchService interface {
|
|||||||
UpdatePigBatch(id uint, dto *dto.PigBatchUpdateDTO) (*dto.PigBatchResponseDTO, error)
|
UpdatePigBatch(id uint, dto *dto.PigBatchUpdateDTO) (*dto.PigBatchResponseDTO, error)
|
||||||
DeletePigBatch(id uint) error
|
DeletePigBatch(id uint) error
|
||||||
ListPigBatches(isActive *bool) ([]*dto.PigBatchResponseDTO, error)
|
ListPigBatches(isActive *bool) ([]*dto.PigBatchResponseDTO, error)
|
||||||
|
// UpdatePigBatchPens 更新猪批次关联的猪栏
|
||||||
|
UpdatePigBatchPens(batchID uint, desiredPenIDs []uint) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type pigBatchService struct {
|
type pigBatchService struct {
|
||||||
logger *logs.Logger
|
logger *logs.Logger
|
||||||
repo repository.PigBatchRepository
|
pigBatchRepo repository.PigBatchRepository // 猪批次仓库
|
||||||
|
pigFarmRepo repository.PigFarmRepository // 猪场资产仓库 (包含猪栏操作)
|
||||||
|
uow repository.UnitOfWork // 工作单元,用于事务管理
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPigBatchService 创建一个新的 PigBatchService 实例
|
// NewPigBatchService 创建一个新的 PigBatchService 实例
|
||||||
func NewPigBatchService(repo repository.PigBatchRepository, logger *logs.Logger) PigBatchService {
|
func NewPigBatchService(pigBatchRepo repository.PigBatchRepository, pigFarmRepo repository.PigFarmRepository, uow repository.UnitOfWork, logger *logs.Logger) PigBatchService {
|
||||||
return &pigBatchService{
|
return &pigBatchService{
|
||||||
logger: logger,
|
logger: logger,
|
||||||
repo: repo,
|
pigBatchRepo: pigBatchRepo,
|
||||||
|
pigFarmRepo: pigFarmRepo,
|
||||||
|
uow: uow,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,7 +79,7 @@ func (s *pigBatchService) CreatePigBatch(dto *dto.PigBatchCreateDTO) (*dto.PigBa
|
|||||||
Status: dto.Status,
|
Status: dto.Status,
|
||||||
}
|
}
|
||||||
|
|
||||||
createdBatch, err := s.repo.CreatePigBatch(batch)
|
createdBatch, err := s.pigBatchRepo.CreatePigBatch(batch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Errorf("创建猪批次失败: %v", err)
|
s.logger.Errorf("创建猪批次失败: %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -78,7 +90,7 @@ func (s *pigBatchService) CreatePigBatch(dto *dto.PigBatchCreateDTO) (*dto.PigBa
|
|||||||
|
|
||||||
// GetPigBatch 处理获取单个猪批次的业务逻辑
|
// GetPigBatch 处理获取单个猪批次的业务逻辑
|
||||||
func (s *pigBatchService) GetPigBatch(id uint) (*dto.PigBatchResponseDTO, error) {
|
func (s *pigBatchService) GetPigBatch(id uint) (*dto.PigBatchResponseDTO, error) {
|
||||||
batch, err := s.repo.GetPigBatchByID(id)
|
batch, err := s.pigBatchRepo.GetPigBatchByID(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
return nil, ErrPigBatchNotFound
|
return nil, ErrPigBatchNotFound
|
||||||
@@ -92,7 +104,7 @@ func (s *pigBatchService) GetPigBatch(id uint) (*dto.PigBatchResponseDTO, error)
|
|||||||
|
|
||||||
// UpdatePigBatch 处理更新猪批次的业务逻辑
|
// UpdatePigBatch 处理更新猪批次的业务逻辑
|
||||||
func (s *pigBatchService) UpdatePigBatch(id uint, dto *dto.PigBatchUpdateDTO) (*dto.PigBatchResponseDTO, error) {
|
func (s *pigBatchService) UpdatePigBatch(id uint, dto *dto.PigBatchUpdateDTO) (*dto.PigBatchResponseDTO, error) {
|
||||||
existingBatch, err := s.repo.GetPigBatchByID(id)
|
existingBatch, err := s.pigBatchRepo.GetPigBatchByID(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
return nil, ErrPigBatchNotFound
|
return nil, ErrPigBatchNotFound
|
||||||
@@ -121,7 +133,7 @@ func (s *pigBatchService) UpdatePigBatch(id uint, dto *dto.PigBatchUpdateDTO) (*
|
|||||||
existingBatch.Status = *dto.Status
|
existingBatch.Status = *dto.Status
|
||||||
}
|
}
|
||||||
|
|
||||||
updatedBatch, err := s.repo.UpdatePigBatch(existingBatch)
|
updatedBatch, err := s.pigBatchRepo.UpdatePigBatch(existingBatch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Errorf("更新猪批次失败,ID: %d, 错误: %v", id, err)
|
s.logger.Errorf("更新猪批次失败,ID: %d, 错误: %v", id, err)
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -133,7 +145,7 @@ func (s *pigBatchService) UpdatePigBatch(id uint, dto *dto.PigBatchUpdateDTO) (*
|
|||||||
// DeletePigBatch 处理删除猪批次的业务逻辑
|
// DeletePigBatch 处理删除猪批次的业务逻辑
|
||||||
func (s *pigBatchService) DeletePigBatch(id uint) error {
|
func (s *pigBatchService) DeletePigBatch(id uint) error {
|
||||||
// 1. 获取猪批次信息
|
// 1. 获取猪批次信息
|
||||||
batch, err := s.repo.GetPigBatchByID(id)
|
batch, err := s.pigBatchRepo.GetPigBatchByID(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
return ErrPigBatchNotFound
|
return ErrPigBatchNotFound
|
||||||
@@ -148,7 +160,7 @@ func (s *pigBatchService) DeletePigBatch(id uint) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 3. 执行删除操作
|
// 3. 执行删除操作
|
||||||
err = s.repo.DeletePigBatch(id)
|
err = s.pigBatchRepo.DeletePigBatch(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) || errors.New("未找到要删除的猪批次").Error() == err.Error() {
|
if errors.Is(err, gorm.ErrRecordNotFound) || errors.New("未找到要删除的猪批次").Error() == err.Error() {
|
||||||
return ErrPigBatchNotFound
|
return ErrPigBatchNotFound
|
||||||
@@ -161,7 +173,7 @@ func (s *pigBatchService) DeletePigBatch(id uint) error {
|
|||||||
|
|
||||||
// ListPigBatches 处理批量查询猪批次的业务逻辑
|
// ListPigBatches 处理批量查询猪批次的业务逻辑
|
||||||
func (s *pigBatchService) ListPigBatches(isActive *bool) ([]*dto.PigBatchResponseDTO, error) {
|
func (s *pigBatchService) ListPigBatches(isActive *bool) ([]*dto.PigBatchResponseDTO, error) {
|
||||||
batches, err := s.repo.ListPigBatches(isActive)
|
batches, err := s.pigBatchRepo.ListPigBatches(isActive)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Errorf("批量查询猪批次失败,错误: %v", err)
|
s.logger.Errorf("批量查询猪批次失败,错误: %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -174,3 +186,112 @@ func (s *pigBatchService) ListPigBatches(isActive *bool) ([]*dto.PigBatchRespons
|
|||||||
|
|
||||||
return responseDTOs, nil
|
return responseDTOs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdatePigBatchPens 更新猪批次关联的猪栏
|
||||||
|
func (s *pigBatchService) UpdatePigBatchPens(batchID uint, desiredPenIDs []uint) error {
|
||||||
|
// 使用工作单元执行事务
|
||||||
|
return s.uow.ExecuteInTransaction(func(tx *gorm.DB) error {
|
||||||
|
// 1. 验证猪批次
|
||||||
|
pigBatch, err := s.pigFarmRepo.GetPigBatchByIDTx(tx, batchID)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return ErrPigBatchNotFound
|
||||||
|
}
|
||||||
|
s.logger.Errorf("更新猪批次猪栏失败: 获取猪批次信息错误,ID: %d, 错误: %v", batchID, err)
|
||||||
|
return fmt.Errorf("获取猪批次信息失败: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !pigBatch.IsActive() {
|
||||||
|
return ErrPigBatchNotActive
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 获取当前关联的猪栏
|
||||||
|
currentPens, err := s.pigFarmRepo.GetPensByBatchID(tx, batchID)
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Errorf("更新猪批次猪栏失败: 获取当前关联猪栏错误,批次ID: %d, 错误: %v", batchID, err)
|
||||||
|
return fmt.Errorf("获取当前关联猪栏失败: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
currentPenMap := make(map[uint]models.Pen)
|
||||||
|
currentPenIDsSet := make(map[uint]struct{})
|
||||||
|
for _, pen := range currentPens {
|
||||||
|
currentPenMap[pen.ID] = pen
|
||||||
|
currentPenIDsSet[pen.ID] = struct{}{} // 用于快速查找
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 构建期望猪栏集合
|
||||||
|
desiredPenIDsSet := make(map[uint]struct{})
|
||||||
|
for _, penID := range desiredPenIDs {
|
||||||
|
desiredPenIDsSet[penID] = struct{}{} // 用于快速查找
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 计算需要添加和移除的猪栏
|
||||||
|
var pensToRemove []uint
|
||||||
|
for penID := range currentPenIDsSet {
|
||||||
|
if _, found := desiredPenIDsSet[penID]; !found {
|
||||||
|
pensToRemove = append(pensToRemove, penID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var pensToAdd []uint
|
||||||
|
for _, penID := range desiredPenIDs {
|
||||||
|
if _, found := currentPenIDsSet[penID]; !found {
|
||||||
|
pensToAdd = append(pensToAdd, penID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 处理移除猪栏
|
||||||
|
for _, penID := range pensToRemove {
|
||||||
|
currentPen := currentPenMap[penID]
|
||||||
|
// 验证:确保猪栏确实与当前批次关联
|
||||||
|
if currentPen.PigBatchID == nil || *currentPen.PigBatchID != batchID {
|
||||||
|
s.logger.Warnf("尝试移除未与批次 %d 关联的猪栏 %d", batchID, penID)
|
||||||
|
return fmt.Errorf("猪栏 %d 未与该批次关联,无法移除", penID)
|
||||||
|
}
|
||||||
|
|
||||||
|
updates := make(map[string]interface{})
|
||||||
|
updates["pig_batch_id"] = nil // 总是将 PigBatchID 设为 nil
|
||||||
|
|
||||||
|
// 只有当猪栏当前状态是“占用”时,才将其状态改回“空闲”
|
||||||
|
if currentPen.Status == models.PenStatusOccupied {
|
||||||
|
updates["status"] = models.PenStatusEmpty
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.pigFarmRepo.UpdatePenFields(tx, penID, updates); err != nil {
|
||||||
|
s.logger.Errorf("更新猪批次猪栏失败: 移除猪栏 %d 失败: %v", penID, err)
|
||||||
|
return fmt.Errorf("移除猪栏 %d 失败: %w", penID, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. 处理添加猪栏
|
||||||
|
for _, penID := range pensToAdd {
|
||||||
|
actualPen, err := s.pigFarmRepo.GetPenByIDTx(tx, penID)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return fmt.Errorf("猪栏 %d 不存在: %w", penID, ErrPenNotFound)
|
||||||
|
}
|
||||||
|
s.logger.Errorf("更新猪批次猪栏失败: 获取猪栏 %d 信息错误: %v", penID, err)
|
||||||
|
return fmt.Errorf("获取猪栏 %d 信息失败: %w", penID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证:猪栏必须是“空闲”状态且未被任何批次占用,才能被分配
|
||||||
|
if actualPen.Status != models.PenStatusEmpty {
|
||||||
|
return fmt.Errorf("猪栏 %s 状态为 %s,无法分配: %w", actualPen.PenNumber, actualPen.Status, ErrPenStatusInvalidForAllocation)
|
||||||
|
}
|
||||||
|
if actualPen.PigBatchID != nil {
|
||||||
|
return fmt.Errorf("猪栏 %s 已被其他批次 %d 占用,无法分配: %w", actualPen.PenNumber, *actualPen.PigBatchID, ErrPenOccupiedByOtherBatch)
|
||||||
|
}
|
||||||
|
|
||||||
|
updates := map[string]interface{}{
|
||||||
|
"pig_batch_id": &batchID, // 将 PigBatchID 设为当前批次ID的指针
|
||||||
|
"status": models.PenStatusOccupied, // 分配后,状态变为“占用”
|
||||||
|
}
|
||||||
|
if err := s.pigFarmRepo.UpdatePenFields(tx, penID, updates); err != nil {
|
||||||
|
s.logger.Errorf("更新猪批次猪栏失败: 添加猪栏 %d 失败: %v", penID, err)
|
||||||
|
return fmt.Errorf("添加猪栏 %d 失败: %w", penID, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -163,8 +163,8 @@ func (s *pigFarmService) DeletePen(id uint) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 检查猪栏是否关联了活跃批次
|
// 检查猪栏是否关联了活跃批次
|
||||||
if pen.PigBatchID != 0 {
|
if *pen.PigBatchID != 0 {
|
||||||
pigBatch, err := s.repo.GetPigBatchByID(pen.PigBatchID)
|
pigBatch, err := s.repo.GetPigBatchByID(*pen.PigBatchID)
|
||||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,9 +74,12 @@ func NewApplication(configPath string) (*Application, error) {
|
|||||||
userActionLogRepo := repository.NewGormUserActionLogRepository(storage.GetDB())
|
userActionLogRepo := repository.NewGormUserActionLogRepository(storage.GetDB())
|
||||||
pigBatchRepo := repository.NewGormPigBatchRepository(storage.GetDB())
|
pigBatchRepo := repository.NewGormPigBatchRepository(storage.GetDB())
|
||||||
|
|
||||||
|
// 初始化事务管理器
|
||||||
|
unitOfWork := repository.NewGormUnitOfWork(storage.GetDB())
|
||||||
|
|
||||||
// --- 业务逻辑处理器初始化 ---
|
// --- 业务逻辑处理器初始化 ---
|
||||||
pigFarmService := service.NewPigFarmService(pigFarmRepo, logger)
|
pigFarmService := service.NewPigFarmService(pigFarmRepo, logger)
|
||||||
pigBatchService := service.NewPigBatchService(pigBatchRepo, logger)
|
pigBatchService := service.NewPigBatchService(pigBatchRepo, pigFarmRepo, unitOfWork, logger)
|
||||||
|
|
||||||
// 初始化审计服务
|
// 初始化审计服务
|
||||||
auditService := audit.NewService(userActionLogRepo, logger)
|
auditService := audit.NewService(userActionLogRepo, logger)
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ type Pen struct {
|
|||||||
gorm.Model
|
gorm.Model
|
||||||
PenNumber string `gorm:"not null;comment:猪栏的唯一编号, 如 A-01"`
|
PenNumber string `gorm:"not null;comment:猪栏的唯一编号, 如 A-01"`
|
||||||
HouseID uint `gorm:"index;comment:所属猪舍ID"`
|
HouseID uint `gorm:"index;comment:所属猪舍ID"`
|
||||||
PigBatchID uint `gorm:"index;comment:关联的猪批次ID"`
|
PigBatchID *uint `gorm:"index;comment:关联的猪批次ID"`
|
||||||
Capacity int `gorm:"not null;comment:设计容量 (头)"`
|
Capacity int `gorm:"not null;comment:设计容量 (头)"`
|
||||||
Status PenStatus `gorm:"not null;index;comment:猪栏当前状态"`
|
Status PenStatus `gorm:"not null;index;comment:猪栏当前状态"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,13 +17,23 @@ type PigFarmRepository interface {
|
|||||||
|
|
||||||
// Pen methods
|
// Pen methods
|
||||||
CreatePen(pen *models.Pen) error
|
CreatePen(pen *models.Pen) error
|
||||||
|
// GetPenByID 根据ID获取单个猪栏 (非事务性)
|
||||||
GetPenByID(id uint) (*models.Pen, error)
|
GetPenByID(id uint) (*models.Pen, error)
|
||||||
|
// GetPenByIDTx 根据ID获取单个猪栏 (事务性)
|
||||||
|
GetPenByIDTx(tx *gorm.DB, id uint) (*models.Pen, error)
|
||||||
ListPens() ([]models.Pen, error)
|
ListPens() ([]models.Pen, error)
|
||||||
UpdatePen(pen *models.Pen) error
|
UpdatePen(pen *models.Pen) error
|
||||||
DeletePen(id uint) error
|
DeletePen(id uint) error
|
||||||
|
// GetPensByBatchID 根据批次ID获取所有关联的猪栏 (事务性)
|
||||||
|
GetPensByBatchID(tx *gorm.DB, batchID uint) ([]models.Pen, error)
|
||||||
|
// UpdatePenFields 更新猪栏的指定字段 (事务性)
|
||||||
|
UpdatePenFields(tx *gorm.DB, penID uint, updates map[string]interface{}) error
|
||||||
|
|
||||||
// PigBatch methods
|
// PigBatch methods
|
||||||
|
// GetPigBatchByID 根据ID获取单个猪批次 (非事务性)
|
||||||
GetPigBatchByID(id uint) (*models.PigBatch, error)
|
GetPigBatchByID(id uint) (*models.PigBatch, error)
|
||||||
|
// GetPigBatchByIDTx 根据ID获取单个猪批次 (事务性)
|
||||||
|
GetPigBatchByIDTx(tx *gorm.DB, id uint) (*models.PigBatch, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// gormPigFarmRepository 是 PigFarmRepository 的 GORM 实现
|
// gormPigFarmRepository 是 PigFarmRepository 的 GORM 实现
|
||||||
@@ -38,10 +48,12 @@ func NewGormPigFarmRepository(db *gorm.DB) PigFarmRepository {
|
|||||||
|
|
||||||
// --- PigHouse Implementation ---
|
// --- PigHouse Implementation ---
|
||||||
|
|
||||||
|
// CreatePigHouse 创建一个新的猪舍
|
||||||
func (r *gormPigFarmRepository) CreatePigHouse(house *models.PigHouse) error {
|
func (r *gormPigFarmRepository) CreatePigHouse(house *models.PigHouse) error {
|
||||||
return r.db.Create(house).Error
|
return r.db.Create(house).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetPigHouseByID 根据ID获取单个猪舍
|
||||||
func (r *gormPigFarmRepository) GetPigHouseByID(id uint) (*models.PigHouse, error) {
|
func (r *gormPigFarmRepository) GetPigHouseByID(id uint) (*models.PigHouse, error) {
|
||||||
var house models.PigHouse
|
var house models.PigHouse
|
||||||
if err := r.db.First(&house, id).Error; err != nil {
|
if err := r.db.First(&house, id).Error; err != nil {
|
||||||
@@ -50,6 +62,7 @@ func (r *gormPigFarmRepository) GetPigHouseByID(id uint) (*models.PigHouse, erro
|
|||||||
return &house, nil
|
return &house, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListPigHouses 列出所有猪舍
|
||||||
func (r *gormPigFarmRepository) ListPigHouses() ([]models.PigHouse, error) {
|
func (r *gormPigFarmRepository) ListPigHouses() ([]models.PigHouse, error) {
|
||||||
var houses []models.PigHouse
|
var houses []models.PigHouse
|
||||||
if err := r.db.Find(&houses).Error; err != nil {
|
if err := r.db.Find(&houses).Error; err != nil {
|
||||||
@@ -58,28 +71,31 @@ func (r *gormPigFarmRepository) ListPigHouses() ([]models.PigHouse, error) {
|
|||||||
return houses, nil
|
return houses, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdatePigHouse 更新一个猪舍
|
||||||
func (r *gormPigFarmRepository) UpdatePigHouse(house *models.PigHouse) error {
|
func (r *gormPigFarmRepository) UpdatePigHouse(house *models.PigHouse) error {
|
||||||
result := r.db.Model(&models.PigHouse{}).Where("id = ?", house.ID).Updates(house)
|
result := r.db.Model(&models.PigHouse{}).Where("id = ?", house.ID).Updates(house)
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
return result.Error
|
return result.Error
|
||||||
}
|
}
|
||||||
if result.RowsAffected == 0 {
|
if result.RowsAffected == 0 {
|
||||||
return gorm.ErrRecordNotFound
|
return gorm.ErrRecordNotFound // 未找到要更新的猪舍或数据未改变
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeletePigHouse 根据ID删除一个猪舍
|
||||||
func (r *gormPigFarmRepository) DeletePigHouse(id uint) error {
|
func (r *gormPigFarmRepository) DeletePigHouse(id uint) error {
|
||||||
result := r.db.Delete(&models.PigHouse{}, id)
|
result := r.db.Delete(&models.PigHouse{}, id)
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
return result.Error
|
return result.Error
|
||||||
}
|
}
|
||||||
if result.RowsAffected == 0 {
|
if result.RowsAffected == 0 {
|
||||||
return gorm.ErrRecordNotFound
|
return gorm.ErrRecordNotFound // 未找到要删除的猪舍
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CountPensInHouse 统计猪舍中的猪栏数量
|
||||||
func (r *gormPigFarmRepository) CountPensInHouse(houseID uint) (int64, error) {
|
func (r *gormPigFarmRepository) CountPensInHouse(houseID uint) (int64, error) {
|
||||||
var count int64
|
var count int64
|
||||||
err := r.db.Model(&models.Pen{}).Where("house_id = ?", houseID).Count(&count).Error
|
err := r.db.Model(&models.Pen{}).Where("house_id = ?", houseID).Count(&count).Error
|
||||||
@@ -88,10 +104,12 @@ func (r *gormPigFarmRepository) CountPensInHouse(houseID uint) (int64, error) {
|
|||||||
|
|
||||||
// --- Pen Implementation ---
|
// --- Pen Implementation ---
|
||||||
|
|
||||||
|
// CreatePen 创建一个新的猪栏
|
||||||
func (r *gormPigFarmRepository) CreatePen(pen *models.Pen) error {
|
func (r *gormPigFarmRepository) CreatePen(pen *models.Pen) error {
|
||||||
return r.db.Create(pen).Error
|
return r.db.Create(pen).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetPenByID 根据ID获取单个猪栏 (非事务性)
|
||||||
func (r *gormPigFarmRepository) GetPenByID(id uint) (*models.Pen, error) {
|
func (r *gormPigFarmRepository) GetPenByID(id uint) (*models.Pen, error) {
|
||||||
var pen models.Pen
|
var pen models.Pen
|
||||||
if err := r.db.First(&pen, id).Error; err != nil {
|
if err := r.db.First(&pen, id).Error; err != nil {
|
||||||
@@ -100,6 +118,16 @@ func (r *gormPigFarmRepository) GetPenByID(id uint) (*models.Pen, error) {
|
|||||||
return &pen, nil
|
return &pen, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetPenByIDTx 根据ID获取单个猪栏 (事务性)
|
||||||
|
func (r *gormPigFarmRepository) GetPenByIDTx(tx *gorm.DB, id uint) (*models.Pen, error) {
|
||||||
|
var pen models.Pen
|
||||||
|
if err := tx.First(&pen, id).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &pen, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListPens 列出所有猪栏
|
||||||
func (r *gormPigFarmRepository) ListPens() ([]models.Pen, error) {
|
func (r *gormPigFarmRepository) ListPens() ([]models.Pen, error) {
|
||||||
var pens []models.Pen
|
var pens []models.Pen
|
||||||
if err := r.db.Find(&pens).Error; err != nil {
|
if err := r.db.Find(&pens).Error; err != nil {
|
||||||
@@ -108,30 +136,50 @@ func (r *gormPigFarmRepository) ListPens() ([]models.Pen, error) {
|
|||||||
return pens, nil
|
return pens, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdatePen 更新一个猪栏
|
||||||
func (r *gormPigFarmRepository) UpdatePen(pen *models.Pen) error {
|
func (r *gormPigFarmRepository) UpdatePen(pen *models.Pen) error {
|
||||||
result := r.db.Model(&models.Pen{}).Where("id = ?", pen.ID).Updates(pen)
|
result := r.db.Model(&models.Pen{}).Where("id = ?", pen.ID).Updates(pen)
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
return result.Error
|
return result.Error
|
||||||
}
|
}
|
||||||
if result.RowsAffected == 0 {
|
if result.RowsAffected == 0 {
|
||||||
return gorm.ErrRecordNotFound
|
return gorm.ErrRecordNotFound // 未找到要更新的猪栏或数据未改变
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeletePen 根据ID删除一个猪栏
|
||||||
func (r *gormPigFarmRepository) DeletePen(id uint) error {
|
func (r *gormPigFarmRepository) DeletePen(id uint) error {
|
||||||
result := r.db.Delete(&models.Pen{}, id)
|
result := r.db.Delete(&models.Pen{}, id)
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
return result.Error
|
return result.Error
|
||||||
}
|
}
|
||||||
if result.RowsAffected == 0 {
|
if result.RowsAffected == 0 {
|
||||||
return gorm.ErrRecordNotFound
|
return gorm.ErrRecordNotFound // 未找到要删除的猪栏
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetPensByBatchID 根据批次ID获取所有关联的猪栏 (事务性)
|
||||||
|
func (r *gormPigFarmRepository) GetPensByBatchID(tx *gorm.DB, batchID uint) ([]models.Pen, error) {
|
||||||
|
var pens []models.Pen
|
||||||
|
// 注意:PigBatchID 是指针类型,需要处理 nil 值
|
||||||
|
result := tx.Where("pig_batch_id = ?", batchID).Find(&pens)
|
||||||
|
if result.Error != nil {
|
||||||
|
return nil, result.Error
|
||||||
|
}
|
||||||
|
return pens, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdatePenFields 更新猪栏的指定字段 (事务性)
|
||||||
|
func (r *gormPigFarmRepository) UpdatePenFields(tx *gorm.DB, penID uint, updates map[string]interface{}) error {
|
||||||
|
result := tx.Model(&models.Pen{}).Where("id = ?", penID).Updates(updates)
|
||||||
|
return result.Error
|
||||||
|
}
|
||||||
|
|
||||||
// --- PigBatch Implementation ---
|
// --- PigBatch Implementation ---
|
||||||
|
|
||||||
|
// GetPigBatchByID 根据ID获取单个猪批次 (非事务性)
|
||||||
func (r *gormPigFarmRepository) GetPigBatchByID(id uint) (*models.PigBatch, error) {
|
func (r *gormPigFarmRepository) GetPigBatchByID(id uint) (*models.PigBatch, error) {
|
||||||
var batch models.PigBatch
|
var batch models.PigBatch
|
||||||
if err := r.db.First(&batch, id).Error; err != nil {
|
if err := r.db.First(&batch, id).Error; err != nil {
|
||||||
@@ -139,3 +187,12 @@ func (r *gormPigFarmRepository) GetPigBatchByID(id uint) (*models.PigBatch, erro
|
|||||||
}
|
}
|
||||||
return &batch, nil
|
return &batch, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetPigBatchByIDTx 根据ID获取单个猪批次 (事务性)
|
||||||
|
func (r *gormPigFarmRepository) GetPigBatchByIDTx(tx *gorm.DB, id uint) (*models.PigBatch, error) {
|
||||||
|
var batch models.PigBatch
|
||||||
|
if err := tx.First(&batch, id).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &batch, nil
|
||||||
|
}
|
||||||
|
|||||||
58
internal/infra/repository/unit_of_work.go
Normal file
58
internal/infra/repository/unit_of_work.go
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UnitOfWork 定义了工作单元接口,用于抽象事务管理
|
||||||
|
type UnitOfWork interface {
|
||||||
|
// ExecuteInTransaction 在一个数据库事务中执行给定的函数。
|
||||||
|
// 如果函数返回错误,事务将被回滚;否则,事务将被提交。
|
||||||
|
// tx 参数是当前事务的 GORM DB 实例,应传递给所有仓库方法。
|
||||||
|
ExecuteInTransaction(fn func(tx *gorm.DB) error) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// gormUnitOfWork 是 UnitOfWork 接口的 GORM 实现
|
||||||
|
type gormUnitOfWork struct {
|
||||||
|
db *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGormUnitOfWork 创建一个新的 gormUnitOfWork 实例
|
||||||
|
func NewGormUnitOfWork(db *gorm.DB) UnitOfWork {
|
||||||
|
return &gormUnitOfWork{db: db}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExecuteInTransaction 实现了 UnitOfWork 接口的事务执行逻辑
|
||||||
|
func (u *gormUnitOfWork) ExecuteInTransaction(fn func(tx *gorm.DB) error) error {
|
||||||
|
tx := u.db.Begin()
|
||||||
|
if tx.Error != nil {
|
||||||
|
return fmt.Errorf("开启事务失败: %w", tx.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
// 可以选择在此处记录 panic 日志
|
||||||
|
// u.logger.Errorf("事务中发生 panic,已回滚: %v", r)
|
||||||
|
} else if tx.Error != nil { // 如果函数执行过程中返回错误,或者事务本身有错误,则回滚
|
||||||
|
tx.Rollback()
|
||||||
|
// 可以选择在此处记录错误日志
|
||||||
|
// u.logger.Errorf("事务执行失败,已回滚: %v", tx.Error)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// 执行业务逻辑函数
|
||||||
|
if err := fn(tx); err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return err // 返回业务逻辑函数中的错误
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提交事务
|
||||||
|
if err := tx.Commit().Error; err != nil {
|
||||||
|
return fmt.Errorf("提交事务失败: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user