Skip to content

many2many

go
type AdminRoleModel struct {
	database.BaseModel
	Name        string                 `gorm:"size:255;not null"`
	Description string                 `gorm:"type:text"`

    Permissions []AdminPermissionModel `gorm:"many2many:admin_role_permissions;joinForeignKey:RoleID;joinReferences:PermissionID"`

}

func (AdminRoleModel) TableName() string {
	return "admin_roles"
}
go
// 这里的数据根据 permission 自动与数据库对其
type AdminPermissionModel struct {
	database.BaseModel

	Key  string `gorm:"size:255;not null;uniqueIndex"`
	Name string `gorm:"size:255;not null"`
	Desc string `gorm:"type:text"`

	// 是否为代码中仍然存在的权限
	Enabled bool `gorm:"not null;default:true"`

	// 可选:用于标记是否系统内置,不允许后台随意删除
	Builtin bool `gorm:"not null;default:true"`
}

func (AdminPermissionModel) TableName() string {
	return "admin_permissions"
}
go
// 关系定义
type AdminRolePermissionModel struct {
	RoleID       int64 `gorm:"not null;uniqueIndex:idx_role_permission"`
	PermissionID int64 `gorm:"not null;uniqueIndex:idx_role_permission"`
}

func (AdminRolePermissionModel) TableName() string {
	return "admin_role_permissions"
}

create

go
func CreateRole(db *gorm.DB, name string, desc string, permissionKeys []string) error {
	return db.Transaction(func(tx *gorm.DB) error {
		var permissions []AdminPermissionModel

		if len(permissionKeys) > 0 {
			if err := tx.
				Where("key IN ?", permissionKeys).
				Where("enabled = ?", true).
				Find(&permissions).Error; err != nil {
				return err
			}
		}

		role := AdminRoleModel{
			Name:        name,
			Description: desc,
			Permissions: permissions,
		}

		return tx.Create(&role).Error
	})
}

select

注意 Preload

go
func GetRoleByID(db *gorm.DB, roleID int64) (*AdminRoleModel, error) {
	var role AdminRoleModel

	err := db.
		Preload("Permissions", "enabled = ?", true).
		First(&role, roleID).
		Error

	if err != nil {
		return nil, err
	}

	return &role, nil
}
go
func ListRoles(db *gorm.DB) ([]AdminRoleModel, error) {
	var roles []AdminRoleModel

	err := db.
		Preload("Permissions", "enabled = ?", true).
		Order("id DESC").
		Find(&roles).
		Error

	return roles, err
}

sql 拼接

go
func GetRolePermissionKeys(db *gorm.DB, roleID int64) ([]string, error) {
	var keys []string

	err := db.
		Table("admin_permissions").
		Select("admin_permissions.key").
		Joins(`
			JOIN admin_role_permissions 
			ON admin_role_permissions.permission_id = admin_permissions.id
		`).
		Where("admin_role_permissions.role_id = ?", roleID).
		Where("admin_permissions.enabled = ?", true).
		Pluck("admin_permissions.key", &keys).
		Error
		 
	return keys, err
}

Pluck 把某一列直接提取到 slice 里

update

Association

Association 专门用来操作“关系”的 API(不是操作表数据本身)

Association 指定 “操作哪个关系字段”

go
func UpdateRoleInfo(db *gorm.DB, roleID int64, name string, desc string) error {
	return db.Model(&AdminRoleModel{}).
		Where("id = ?", roleID).
		Updates(map[string]any{
			"name":        name,
			"description": desc,
		}).Error
}

替换权限

go
func ReplaceRolePermissions(db *gorm.DB, roleID int64, permissionKeys []string) error {
	return db.Transaction(func(tx *gorm.DB) error {
		var role AdminRoleModel

		if err := tx.First(&role, roleID).Error; err != nil {
			return err
		}

		var permissions []AdminPermissionModel

		if len(permissionKeys) > 0 {
			if err := tx.
				Where("key IN ?", permissionKeys).
				Where("enabled = ?", true).
				Find(&permissions).
				Error; err != nil {
				return err
			}
		}

		return tx.Model(&role).
			Association("Permissions").
			Replace(permissions)
	})
}

追加权限

go
db.Model(&role).Association("Permissions").Append(perms)

移除权限

go
db.Model(&role).Association("Permissions").Delete(perms)

清空权限

go
db.Model(&role).Association("Permissions").Clear()

Find(查询关系)

go
var perms []AdminPermissionModel
db.Model(&role).Association("Permissions").Find(&perms)

delete

go
func DeleteRole(db *gorm.DB, roleID int64) error {
	return db.Transaction(func(tx *gorm.DB) error {
		var role AdminRoleModel

		if err := tx.First(&role, roleID).Error; err != nil {
			return err
		}

		if err := tx.Model(&role).
			Association("Permissions").
			Clear(); err != nil {
			return err
		}

		return tx.Delete(&role).Error
	})
}