Go语言 当我在更新时,有些字段不是必填的,我该如何处理动态查询?

tktrz96b  于 2023-01-22  发布在  Go
关注(0)|答案(2)|浏览(171)

这里有一个例子可以说明我的意思:

func (s *Store) UpdateOrganization(entity *Organization) (*Organization, error) {
    org := &Organization{}
    stmt := `
        UPDATE public.organizations
        SET name = $1,
            website = $2,
            image_url = $3
        WHERE id = $4
        RETURNING *;`

    rows, _ := s.db.Query(
        context.Background(),
        stmt,
        entity.Name,
        entity.Website,
        entity.ImageURL,
        entity.ID,
    )

    if err := pgxscan.ScanOne(org, rows); err != nil {
        return nil, newStoreError(err)
    }

    return org, nil
}

这些字段(namewebsiteimage_url)都不是必需的(补丁更新),因此从UpdateOrganizationDTO生成的实体可能只有name = "george jungle",其他字段(websiteimage_url)为nil
我该如何处理这种情况?否则,我会用空值覆盖DB中的现有字段。
我一直在尝试的一件事(WIP,还不确定这是否是一个好方法,特别是当我有更复杂的查询时)是创建一个Mapmap[string]string,它将非空值Map到它们的列名。
我尝试使用下面注解中提到的条件,现在我想知道如何将值传递给Query()

setClauses := []string{}

if entity.Name != nil {
    setClauses = append(setClauses, "name = $2")
}

if entity.Website != nil {
    setClauses = append(setClauses, "website = $3")
}

if entity.ImageURL != nil {
    setClauses = append(setClauses, "image_url = $4")
}

setClause := ""

stmt := fmt.Sprintf(`
    UPDATE public.organizations
    SET %s
    WHERE id = $1
    RETURNING *;`, setClause)

rows, _ := s.db.Query(
    context.Background(),
    stmt,
    entity.ID,
////// how to handle these VVVVV
    entity.Name,
    entity.Website,
    entity.ImageURL,
)
blmhpbnm

blmhpbnm1#

我想我成功了......
请告诉我是否有更好的办法

func (s *Store) UpdateOrganization(entity *Organization) (*Organization, error) {
    org := &Organization{}

    setClauses := []string{}
    var queryArgs []interface{}

    queryArgs = append(queryArgs, entity.ID)

    if entity.Name != nil {
        setClauses = append(setClauses, "name = $2")
        queryArgs = append(queryArgs, entity.Name)
    }

    if entity.Website != nil {
        setClauses = append(setClauses, "website = $3")
        queryArgs = append(queryArgs, entity.Website)
    }

    if entity.ImageURL != nil {
        setClauses = append(setClauses, "image_url = $4")
        queryArgs = append(queryArgs, entity.ImageURL)
    }

    setClause := strings.Join(setClauses, ",")

    stmt := fmt.Sprintf(`
    UPDATE public.organizations
    SET %s
    WHERE id = $1
    RETURNING *;`, setClause)

    rows, _ := s.db.Query(
        context.Background(),
        stmt,
        queryArgs...,
    )

    if err := pgxscan.ScanOne(org, rows); err != nil {
        return nil, newStoreError(err)
    }

    return org, nil
}
4ktjp1zp

4ktjp1zp2#

您可以执行以下操作:

func (s *Store) UpdateOrganization(entity *Organization) (*Organization, error) {
    org := &Organization{}
    stmt := `
        UPDATE public.organizations
        SET name = COALESCE($1, name),
            website = COALESCE($2, website),
            image_url = COALESCE($3, image_url)
        WHERE id = $4
        RETURNING *;`

    rows, _ := s.db.Query(
        context.Background(),
        stmt,
        entity.Name,
        entity.Website,
        entity.ImageURL,
        entity.ID,
    )

    if err := pgxscan.ScanOne(org, rows); err != nil {
        return nil, newStoreError(err)
    }

    return org, nil
}

然而,我个人认为正确的默认方法(例外情况除外)是从数据库中检索完整的对象;然后在Go语言中修改用户提供的字段;然后照原样存储该对象。

相关问题