- Go + Gin + GORM + PostgreSQL backend - RESTful API for material management - Docker deployment support - Database partitioning for billion-scale data - API documentation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
105 lines
2.8 KiB
Go
105 lines
2.8 KiB
Go
package repository
|
||
|
||
import (
|
||
"material_texture/internal/models"
|
||
|
||
"gorm.io/gorm"
|
||
"gorm.io/gorm/clause"
|
||
)
|
||
|
||
type BindingRepository struct {
|
||
db *gorm.DB
|
||
}
|
||
|
||
func NewBindingRepository(db *gorm.DB) *BindingRepository {
|
||
return &BindingRepository{db: db}
|
||
}
|
||
|
||
// BindMaterial 绑定材质到多个group_id(幂等操作,使用upsert)
|
||
// 优化: 分批处理,避免单条 SQL 过大
|
||
func (r *BindingRepository) BindMaterial(materialID int64, groupIDs []string) error {
|
||
const batchSize = 1000 // 每批最多 1000 条
|
||
|
||
for i := 0; i < len(groupIDs); i += batchSize {
|
||
end := i + batchSize
|
||
if end > len(groupIDs) {
|
||
end = len(groupIDs)
|
||
}
|
||
|
||
batch := groupIDs[i:end]
|
||
bindings := make([]models.MaterialBinding, len(batch))
|
||
for j, groupID := range batch {
|
||
bindings[j] = models.MaterialBinding{
|
||
MaterialID: materialID,
|
||
GroupID: groupID,
|
||
}
|
||
}
|
||
|
||
// 使用 ON CONFLICT DO NOTHING 实现幂等
|
||
if err := r.db.Clauses(clause.OnConflict{
|
||
Columns: []clause.Column{{Name: "material_id"}, {Name: "group_id"}},
|
||
DoNothing: true,
|
||
}).Create(&bindings).Error; err != nil {
|
||
return err
|
||
}
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// UnbindMaterial 解绑材质与指定的group_id
|
||
func (r *BindingRepository) UnbindMaterial(materialID int64, groupIDs []string) error {
|
||
return r.db.Where("material_id = ? AND group_id IN ?", materialID, groupIDs).
|
||
Delete(&models.MaterialBinding{}).Error
|
||
}
|
||
|
||
// GetGroupsByMaterialID 根据材质ID获取所有关联的group_id (分页版本)
|
||
func (r *BindingRepository) GetGroupsByMaterialID(materialID int64, page, pageSize int) ([]string, int64, error) {
|
||
var groupIDs []string
|
||
var total int64
|
||
|
||
db := r.db.Model(&models.MaterialBinding{}).Where("material_id = ?", materialID)
|
||
|
||
// 获取总数
|
||
if err := db.Count(&total).Error; err != nil {
|
||
return nil, 0, err
|
||
}
|
||
|
||
// 分页查询
|
||
offset := (page - 1) * pageSize
|
||
err := db.Order("created_at DESC").
|
||
Offset(offset).
|
||
Limit(pageSize).
|
||
Pluck("group_id", &groupIDs).Error
|
||
|
||
return groupIDs, total, err
|
||
}
|
||
|
||
// GetMaterialsByGroupIDs 根据多个group_id获取关联的材质(含材质详情)
|
||
func (r *BindingRepository) GetMaterialsByGroupIDs(groupIDs []string) ([]models.GroupMaterialResult, error) {
|
||
var bindings []models.MaterialBinding
|
||
|
||
err := r.db.Preload("Material").
|
||
Where("group_id IN ?", groupIDs).
|
||
Find(&bindings).Error
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
results := make([]models.GroupMaterialResult, len(bindings))
|
||
for i, binding := range bindings {
|
||
results[i] = models.GroupMaterialResult{
|
||
GroupID: binding.GroupID,
|
||
Material: binding.Material,
|
||
}
|
||
}
|
||
|
||
return results, nil
|
||
}
|
||
|
||
// DeleteByMaterialID 删除材质的所有绑定(材质删除时级联调用)
|
||
func (r *BindingRepository) DeleteByMaterialID(materialID int64) error {
|
||
return r.db.Where("material_id = ?", materialID).
|
||
Delete(&models.MaterialBinding{}).Error
|
||
}
|