diff --git a/internal/infra/database/seeder.go b/internal/infra/database/seeder.go index f992bb2..fd895ed 100644 --- a/internal/infra/database/seeder.go +++ b/internal/infra/database/seeder.go @@ -18,13 +18,22 @@ import ( ) // SeederFunc 定义了处理一种特定类型预设数据文件的函数签名。 -type SeederFunc func(tx *gorm.DB, jsonData []byte) error +type SeederFunc func(ctx context.Context, tx *gorm.DB, jsonData []byte) error + +// isTableEmpty 检查给定模型对应的数据库表是否为空。 +func isTableEmpty(tx *gorm.DB, model interface{}) (bool, error) { + var count int64 + if err := tx.Model(model).Count(&count).Error; err != nil { + return false, fmt.Errorf("查询表记录数失败: %w", err) + } + return count == 0, nil +} // SeedFromPreset 是一个通用的数据播种函数。 // 它会读取指定目录下的所有 .json 文件,并根据文件内容中的 "type" 字段进行分发。 // 同时,它会校验所有必需的预设类型是否都已成功加载。 func SeedFromPreset(ctx context.Context, db *gorm.DB, presetDir string) error { - logger := logs.TraceLogger(ctx, ctx, "SeedFromPreset") + seedCtx, logger := logs.Trace(ctx, ctx, "SeedFromPreset") // 定义必须存在的预设数据类型及其处理顺序 // 确保 "nutrient" 在 "pig_nutrient_requirements" 之前处理,因为后者依赖于前者。 @@ -97,7 +106,7 @@ func SeedFromPreset(ctx context.Context, db *gorm.DB, presetDir string) error { for _, jsonData := range jsonDatas { // 获取原始文件路径用于错误报告 originalFilePath := typeToFileMap[dataTypeStr] - if err := seederFunc(tx, jsonData); err != nil { + if err := seederFunc(seedCtx, tx, jsonData); err != nil { return fmt.Errorf("处理文件 (type: %s, path: %s) 时发生错误: %w", dataTypeStr, originalFilePath, err) } } @@ -126,7 +135,19 @@ type rawMaterialInfo struct { } // seedNutrients 先严格校验JSON源文件,然后以“有则跳过”的模式播种数据。 -func seedNutrients(tx *gorm.DB, jsonData []byte) error { +func seedNutrients(ctx context.Context, tx *gorm.DB, jsonData []byte) error { + logger := logs.GetLogger(ctx) + + // 检查 Nutrient 表是否为空,如果非空则跳过播种 + isEmpty, err := isTableEmpty(tx, &models.Nutrient{}) + if err != nil { + return fmt.Errorf("检查 Nutrient 表是否为空失败: %w", err) + } + if !isEmpty { + logger.Info("已存在原料数据, 跳过数据播种") + return nil + } + // 1. 严格校验JSON文件,检查内部重复键 if err := validateAndParseNutrientJSON(jsonData); err != nil { return fmt.Errorf("JSON源文件校验失败: %w", err) @@ -154,7 +175,6 @@ func seedNutrients(tx *gorm.DB, jsonData []byte) error { // 3. 将通过校验的、干净的数据写入数据库 dataNode := gjson.GetBytes(jsonData, "data") - var err error // 用于捕获 ForEach 内部的错误 dataNode.ForEach(func(rawMaterialKey, rawMaterialValue gjson.Result) bool { rawMaterialName := rawMaterialKey.String() var rawMaterial models.RawMaterial @@ -213,7 +233,19 @@ func seedNutrients(tx *gorm.DB, jsonData []byte) error { } // seedPigNutrientRequirements 先严格校验JSON源文件,然后以“有则跳过”的模式播种数据。 -func seedPigNutrientRequirements(tx *gorm.DB, jsonData []byte) error { +func seedPigNutrientRequirements(ctx context.Context, tx *gorm.DB, jsonData []byte) error { + logger := logs.GetLogger(ctx) + + // 检查 PigBreed 表是否为空,如果非空则跳过播种 + isEmpty, err := isTableEmpty(tx, &models.PigBreed{}) + if err != nil { + return fmt.Errorf("检查 PigBreed 表是否为空失败: %w", err) + } + if !isEmpty { + logger.Info("已存在猪种数据, 跳过数据播种") + return nil + } + // 1. 严格校验JSON文件,检查内部重复键 if err := validateAndParsePigNutrientRequirementJSON(jsonData); err != nil { return fmt.Errorf("JSON源文件校验失败: %w", err) @@ -271,7 +303,6 @@ func seedPigNutrientRequirements(tx *gorm.DB, jsonData []byte) error { // 3. 将通过校验的、干净的数据写入数据库 dataNode := gjson.GetBytes(jsonData, "data") - var err error // 用于捕获 ForEach 内部的错误 dataNode.ForEach(func(breedKey, breedValue gjson.Result) bool { breedName := breedKey.String() var pigBreed models.PigBreed