Golang中使用GORM更新记录及其关联关系的方法

Golang中使用GORM更新记录及其关联关系的方法 大家好,Gophers。

这是我的实体:

type DishEntity struct {
	gorm.Model
	Date        time.Time
	Ingredients []MeasuredIngredientEntity `gorm:"many2many:dish_measuredingredient;"`
}

这是我的更新函数:

func UpdateDish(db *gorm.DB, d entities.DishEntity) error {
	if err := db.Updates(&d).Error; err != nil {
		return err
	}
	return nil
}

我的问题是:

当我向菜品中添加新配料时,它按预期工作,但当我移除某些配料时,数据库中没有反映出这个更改。

我知道这不是我应该做的正确方式,那么我应该选择哪种策略呢?

GPT给了我多种解决方案,但它们都有一些错误和意想不到的行为。


更多关于Golang中使用GORM更新记录及其关联关系的方法的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

你试过用 Replace 吗?

是的,但没用。

我通过彻底改变方法解决了我的问题。我没有尝试在单个查询中更新包含食材的日期,而是为食材单独创建了一个仓库,在其函数中以 dayID 作为参数。

这个话题可以关闭了。

更多关于Golang中使用GORM更新记录及其关联关系的方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你尝试过使用 Replace 吗?

GORM

关联

自动创建/更新 GORM 在创建或更新记录时,会自动保存关联及其引用,它使用一种 upsert 技术,主要更新现有记录的外键引用。

在GORM中更新多对多关联时,需要明确处理关联的替换操作。以下是几种有效的解决方案:

方案1:使用Replace方法(推荐)

func UpdateDish(db *gorm.DB, d entities.DishEntity) error {
    // 先更新基本字段
    if err := db.Model(&d).Updates(map[string]interface{}{
        "date": d.Date,
    }).Error; err != nil {
        return err
    }
    
    // 替换关联的配料
    if err := db.Model(&d).Association("Ingredients").Replace(d.Ingredients).Error; err != nil {
        return err
    }
    
    return nil
}

方案2:完整事务处理

func UpdateDish(db *gorm.DB, d entities.DishEntity) error {
    return db.Transaction(func(tx *gorm.DB) error {
        // 更新菜品基本字段
        if err := tx.Model(&d).Updates(map[string]interface{}{
            "date": d.Date,
        }).Error; err != nil {
            return err
        }
        
        // 清除现有关联
        if err := tx.Model(&d).Association("Ingredients").Clear().Error; err != nil {
            return err
        }
        
        // 添加新的关联
        if len(d.Ingredients) > 0 {
            if err := tx.Model(&d).Association("Ingredients").Append(d.Ingredients).Error; err != nil {
                return err
            }
        }
        
        return nil
    })
}

方案3:使用Select更新关联

func UpdateDish(db *gorm.DB, d entities.DishEntity) error {
    // 使用Select明确指定更新的字段和关联
    if err := db.Session(&gorm.Session{FullSaveAssociations: false}).
        Select("*").
        Omit("Ingredients.*").
        Updates(&d).Error; err != nil {
        return err
    }
    
    // 处理关联更新
    if err := db.Model(&d).Association("Ingredients").Replace(d.Ingredients).Error; err != nil {
        return err
    }
    
    return nil
}

方案4:预加载后更新

func UpdateDish(db *gorm.DB, dishID uint, updatedDish entities.DishEntity) error {
    var existingDish entities.DishEntity
    
    // 预加载现有关联
    if err := db.Preload("Ingredients").First(&existingDish, dishID).Error; err != nil {
        return err
    }
    
    return db.Transaction(func(tx *gorm.DB) error {
        // 更新基本字段
        if err := tx.Model(&existingDish).Updates(map[string]interface{}{
            "date": updatedDish.Date,
        }).Error; err != nil {
            return err
        }
        
        // 替换关联
        if err := tx.Model(&existingDish).Association("Ingredients").
            Replace(updatedDish.Ingredients).Error; err != nil {
            return err
        }
        
        return nil
    })
}

关键点说明:

  1. Updates()方法不会自动处理多对多关联的删除,它只处理添加和更新
  2. Association().Replace() 是处理关联替换的标准方法
  3. 事务处理确保数据一致性
  4. 预加载现有数据可以避免并发问题

推荐使用方案1或方案4,它们能正确处理配料的添加、更新和删除操作。

回到顶部