定义猪的模型和营养需求模型
This commit is contained in:
@@ -51,4 +51,5 @@ http://git.huangwc.com/pig/pig-farm-controller/issues/66
|
|||||||
1. 定义原料表, 营养表, 原料营养表, 原料库存变更表
|
1. 定义原料表, 营养表, 原料营养表, 原料库存变更表
|
||||||
2. 迁移配置文件, 实现从json文件中读取原材料营养预设值, 并自动写入数据库
|
2. 迁移配置文件, 实现从json文件中读取原材料营养预设值, 并自动写入数据库
|
||||||
3. 定义配方领域, 实现营养元素的增删改查
|
3. 定义配方领域, 实现营养元素的增删改查
|
||||||
4. 实现原材料的增删改查和仓库层的原料库存记录表增查
|
4. 实现原材料的增删改查和仓库层的原料库存记录表增查
|
||||||
|
5. 定义猪的模型和营养需求模型
|
||||||
@@ -250,9 +250,20 @@ func (ps *PostgresStorage) applyCompressionPolicies(ctx context.Context) error {
|
|||||||
|
|
||||||
// creatingIndex 用于创建gorm无法处理的索引, 如gin索引
|
// creatingIndex 用于创建gorm无法处理的索引, 如gin索引
|
||||||
func (ps *PostgresStorage) creatingIndex(ctx context.Context) error {
|
func (ps *PostgresStorage) creatingIndex(ctx context.Context) error {
|
||||||
storageCtx, logger := logs.Trace(ctx, ps.ctx, "creatingIndex")
|
storageCtx := logs.AddFuncName(ctx, ps.ctx, "creatingIndex")
|
||||||
// 使用 IF NOT EXISTS 保证幂等性
|
// 使用 IF NOT EXISTS 保证幂等性
|
||||||
// 如果索引已存在,此命令不会报错
|
// 如果索引已存在,此命令不会报错
|
||||||
|
if err := ps.creatingUniqueIndex(storageCtx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := ps.createGinIndexes(storageCtx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ps *PostgresStorage) creatingUniqueIndex(ctx context.Context) error {
|
||||||
|
storageCtx, logger := logs.Trace(ctx, ps.ctx, "creatingUniqueIndex")
|
||||||
|
|
||||||
// 为 raw_material_nutrients 表创建部分唯一索引,以兼容软删除
|
// 为 raw_material_nutrients 表创建部分唯一索引,以兼容软删除
|
||||||
logger.Debug("正在为 raw_material_nutrients 表创建部分唯一索引")
|
logger.Debug("正在为 raw_material_nutrients 表创建部分唯一索引")
|
||||||
@@ -263,6 +274,47 @@ func (ps *PostgresStorage) creatingIndex(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
logger.Debug("成功为 raw_material_nutrients 创建部分唯一索引 (或已存在)")
|
logger.Debug("成功为 raw_material_nutrients 创建部分唯一索引 (或已存在)")
|
||||||
|
|
||||||
|
// 为 pig_breeds 表创建部分唯一索引,以兼容软删除 (name 唯一)
|
||||||
|
logger.Debug("正在为 pig_breeds 表创建部分唯一索引")
|
||||||
|
partialIndexSQL = "CREATE UNIQUE INDEX IF NOT EXISTS idx_pig_breeds_unique_name_when_not_deleted ON pig_breeds (name) WHERE deleted_at IS NULL;"
|
||||||
|
if err := ps.db.WithContext(storageCtx).Exec(partialIndexSQL).Error; err != nil {
|
||||||
|
logger.Errorw("为 pig_breeds 创建部分唯一索引失败", "error", err)
|
||||||
|
return fmt.Errorf("为 pig_breeds 创建部分唯一索引失败: %w", err)
|
||||||
|
}
|
||||||
|
logger.Debug("成功为 pig_breeds 创建部分唯一索引 (或已存在)")
|
||||||
|
|
||||||
|
// 为 pig_age_stages 表创建部分唯一索引,以兼容软删除 (name 唯一)
|
||||||
|
logger.Debug("正在为 pig_age_stages 表创建部分唯一索引")
|
||||||
|
partialIndexSQL = "CREATE UNIQUE INDEX IF NOT EXISTS idx_pig_age_stages_unique_name_when_not_deleted ON pig_age_stages (name) WHERE deleted_at IS NULL;"
|
||||||
|
if err := ps.db.WithContext(storageCtx).Exec(partialIndexSQL).Error; err != nil {
|
||||||
|
logger.Errorw("为 pig_age_stages 创建部分唯一索引失败", "error", err)
|
||||||
|
return fmt.Errorf("为 pig_age_stages 创建部分唯一索引失败: %w", err)
|
||||||
|
}
|
||||||
|
logger.Debug("成功为 pig_age_stages 创建部分唯一索引 (或已存在)")
|
||||||
|
|
||||||
|
// 为 pig_types 表创建部分唯一索引,以兼容软删除 (breed_id, age_stage_id 组合唯一)
|
||||||
|
logger.Debug("正在为 pig_types 表创建部分唯一索引")
|
||||||
|
partialIndexSQL = "CREATE UNIQUE INDEX IF NOT EXISTS idx_pig_types_unique_breed_age_stage_when_not_deleted ON pig_types (breed_id, age_stage_id) WHERE deleted_at IS NULL;"
|
||||||
|
if err := ps.db.WithContext(storageCtx).Exec(partialIndexSQL).Error; err != nil {
|
||||||
|
logger.Errorw("为 pig_types 创建部分唯一索引失败", "error", err)
|
||||||
|
return fmt.Errorf("为 pig_types 创建部分唯一索引失败: %w", err)
|
||||||
|
}
|
||||||
|
logger.Debug("成功为 pig_types 创建部分唯一索引 (或已存在)")
|
||||||
|
|
||||||
|
// 为 pig_nutrient_requirements 表创建部分唯一索引,以兼容软删除 (pig_type_id, nutrient_id 组合唯一)
|
||||||
|
logger.Debug("正在为 pig_nutrient_requirements 表创建部分唯一索引")
|
||||||
|
partialIndexSQL = "CREATE UNIQUE INDEX IF NOT EXISTS idx_pig_nutrient_requirements_unique_type_nutrient_when_not_deleted ON pig_nutrient_requirements (pig_type_id, nutrient_id) WHERE deleted_at IS NULL;"
|
||||||
|
if err := ps.db.WithContext(storageCtx).Exec(partialIndexSQL).Error; err != nil {
|
||||||
|
logger.Errorw("为 pig_nutrient_requirements 创建部分唯一索引失败", "error", err)
|
||||||
|
return fmt.Errorf("为 pig_nutrient_requirements 创建部分唯一索引失败: %w", err)
|
||||||
|
}
|
||||||
|
logger.Debug("成功为 pig_nutrient_requirements 创建部分唯一索引 (或已存在)")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ps *PostgresStorage) createGinIndexes(ctx context.Context) error {
|
||||||
|
storageCtx, logger := logs.Trace(ctx, ps.ctx, "createGinIndexes")
|
||||||
|
|
||||||
// 为 sensor_data 表的 data 字段创建 GIN 索引
|
// 为 sensor_data 表的 data 字段创建 GIN 索引
|
||||||
logger.Debug("正在为 sensor_data 表的 data 字段创建 GIN 索引")
|
logger.Debug("正在为 sensor_data 表的 data 字段创建 GIN 索引")
|
||||||
ginSensorDataIndexSQL := "CREATE INDEX IF NOT EXISTS idx_sensor_data_data_gin ON sensor_data USING GIN (data);"
|
ginSensorDataIndexSQL := "CREATE INDEX IF NOT EXISTS idx_sensor_data_data_gin ON sensor_data USING GIN (data);"
|
||||||
@@ -280,6 +332,5 @@ func (ps *PostgresStorage) creatingIndex(ctx context.Context) error {
|
|||||||
return fmt.Errorf("为 tasks 的 parameters 字段创建 GIN 索引失败: %w", err)
|
return fmt.Errorf("为 tasks 的 parameters 字段创建 GIN 索引失败: %w", err)
|
||||||
}
|
}
|
||||||
logger.Debug("成功为 tasks 的 parameters 字段创建 GIN 索引 (或已存在)")
|
logger.Debug("成功为 tasks 的 parameters 字段创建 GIN 索引 (或已存在)")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,10 @@ func GetAllModels() []interface{} {
|
|||||||
&WeighingRecord{},
|
&WeighingRecord{},
|
||||||
&PigTransferLog{},
|
&PigTransferLog{},
|
||||||
&PigSickLog{},
|
&PigSickLog{},
|
||||||
|
&PigBreed{},
|
||||||
|
&PigAgeStage{},
|
||||||
|
&PigType{},
|
||||||
|
&PigNutrientRequirement{},
|
||||||
|
|
||||||
// Pig Buy & Sell
|
// Pig Buy & Sell
|
||||||
&PigPurchase{},
|
&PigPurchase{},
|
||||||
@@ -119,7 +123,7 @@ func (a *UintArray) Scan(src interface{}) error {
|
|||||||
case string:
|
case string:
|
||||||
srcStr = v
|
srcStr = v
|
||||||
default:
|
default:
|
||||||
return errors.New("无法扫描非字符串或字节类型的源到 UintArray")
|
return errors.New("无法将值 %v (类型 %T) 扫描为 UintArray")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 去掉花括号
|
// 去掉花括号
|
||||||
|
|||||||
43
internal/infra/models/pig.go
Normal file
43
internal/infra/models/pig.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
// PigBreed 猪品种模型
|
||||||
|
type PigBreed struct {
|
||||||
|
Model
|
||||||
|
Name string `gorm:"size:50;not null;comment:品种名称"`
|
||||||
|
Description string `gorm:"size:255;comment:品种描述"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (PigBreed) TableName() string {
|
||||||
|
return "pig_breeds"
|
||||||
|
}
|
||||||
|
|
||||||
|
// PigAgeStage 猪年龄阶段模型
|
||||||
|
type PigAgeStage struct {
|
||||||
|
Model
|
||||||
|
Name string `gorm:"size:50;not null;comment:年龄阶段名称 (如: 仔猪, 生长猪, 育肥猪)"`
|
||||||
|
Description string `gorm:"size:255;comment:阶段描述"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (PigAgeStage) TableName() string {
|
||||||
|
return "pig_age_stages"
|
||||||
|
}
|
||||||
|
|
||||||
|
// PigType 猪类型模型,代表特定品种和年龄阶段的组合
|
||||||
|
type PigType struct {
|
||||||
|
Model
|
||||||
|
BreedID uint32 `gorm:"not null;index;comment:关联的猪品种ID"`
|
||||||
|
Breed PigBreed `gorm:"foreignKey:BreedID"`
|
||||||
|
AgeStageID uint32 `gorm:"not null;index;comment:关联的猪年龄阶段ID"`
|
||||||
|
AgeStage PigAgeStage `gorm:"foreignKey:AgeStageID"`
|
||||||
|
Description string `gorm:"size:255;comment:该猪类型的描述或特点"`
|
||||||
|
DailyFeedIntake float32 `gorm:"comment:理论日均食量 (g/天)"`
|
||||||
|
DailyGainWeight float32 `gorm:"comment:理论日增重 (g/天)"`
|
||||||
|
MinDays uint32 `gorm:"comment:该猪类型在该年龄阶段的最小日龄"`
|
||||||
|
MaxDays uint32 `gorm:"comment:该猪类型在该年龄阶段的最大日龄"`
|
||||||
|
MinWeight float32 `gorm:"comment:该猪类型在该年龄阶段的最小体重 (g)"`
|
||||||
|
MaxWeight float32 `gorm:"comment:该猪类型在该年龄阶段的最大体重 (g)"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (PigType) TableName() string {
|
||||||
|
return "pig_types"
|
||||||
|
}
|
||||||
16
internal/infra/models/pig_nutrient.go
Normal file
16
internal/infra/models/pig_nutrient.go
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
// PigNutrientRequirement 猪营养需求模型
|
||||||
|
type PigNutrientRequirement struct {
|
||||||
|
Model
|
||||||
|
PigTypeID uint32 `gorm:"not null;index;comment:关联的猪类型ID"`
|
||||||
|
PigType PigType `gorm:"foreignKey:PigTypeID"`
|
||||||
|
NutrientID uint32 `gorm:"not null;index;comment:关联的营养素ID"`
|
||||||
|
Nutrient Nutrient `gorm:"foreignKey:NutrientID"`
|
||||||
|
MinRequirement float32 `gorm:"not null;comment:最低营养需求量"`
|
||||||
|
MaxRequirement float32 `gorm:"not null;comment:最高营养需求量"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (PigNutrientRequirement) TableName() string {
|
||||||
|
return "pig_nutrient_requirements"
|
||||||
|
}
|
||||||
@@ -129,7 +129,9 @@ internal/infra/models/farm_asset.go
|
|||||||
internal/infra/models/medication.go
|
internal/infra/models/medication.go
|
||||||
internal/infra/models/models.go
|
internal/infra/models/models.go
|
||||||
internal/infra/models/notify.go
|
internal/infra/models/notify.go
|
||||||
|
internal/infra/models/pig.go
|
||||||
internal/infra/models/pig_batch.go
|
internal/infra/models/pig_batch.go
|
||||||
|
internal/infra/models/pig_nutrient.go
|
||||||
internal/infra/models/pig_sick.go
|
internal/infra/models/pig_sick.go
|
||||||
internal/infra/models/pig_trade.go
|
internal/infra/models/pig_trade.go
|
||||||
internal/infra/models/pig_transfer.go
|
internal/infra/models/pig_transfer.go
|
||||||
|
|||||||
Reference in New Issue
Block a user