如何仅编辑数据库中的某些字段而不是全部字段?

huangapple go评论89阅读模式
英文:

How to edit only some fields in the database instead of all?

问题

我有一个使用Go语言编写的应用程序,其中有一个用于编辑用户信息的端点。但我发现一个问题,如果在JSON中看到空白信息(假设用户只想编辑姓名,并将其他字段留空),数据将在数据库中被编辑,并且空白的信息将覆盖数据库中的信息,即使用户不想编辑它们。

我该如何使只有JSON中到达的字段才能在数据库中被有效地编辑?或者有更好的方法吗?

期待您的回答!

我的控制器

func EditUser(w http.ResponseWriter, r *http.Request) {
    params := mux.Vars(r)
    userID, err := strconv.ParseUint(params["userID"], 10, 64)
    if err != nil {
        returns.ERROR(w, http.StatusInternalServerError, err)
        return
    }

    userIDInToken, err := auth.ExtractUserID(r)
    if err != nil {
        returns.ERROR(w, http.StatusInternalServerError, err)
        return
    }

    if userIDInToken != userID {
        returns.ERROR(w, http.StatusForbidden, errors.New("you can't update other user"))
        return
    }

    bodyRequest, err := ioutil.ReadAll(r.Body)
    if err != nil {
        returns.ERROR(w, http.StatusBadRequest, err)
        return
    }

    var user models.User

    if err := json.Unmarshal(bodyRequest, &user); err != nil {
        returns.ERROR(w, http.StatusUnprocessableEntity, err)
        return
    }

    db, err := db.ConnectToDB()
    if err != nil {
        returns.ERROR(w, http.StatusInternalServerError, err)
        return
    }
    defer db.Close()

    repository := repositories.NewUsersRepository(db)
    if err := repository.UpdateUserInfo(userID, user); err != nil {
        returns.ERROR(w, http.StatusInternalServerError, err)
        return
    }

    returns.JSON_RESPONSE(w, http.StatusOK, nil)
}

我的存储库(访问数据库)

func (repository Users) UpdateUserInfo(userID uint64, user models.User) error {
    stmt, err := repository.db.Prepare(
        "UPDATE user SET name = ?, cpf = ?, email = ?, password = ?, city = ?, state = ? WHERE id = ?")
    if err != nil {
        return err
    }
    defer stmt.Close()

    if _, err := stmt.Exec(
        user.Name,
        user.CPF,
        user.Email,
        user.Password,
        user.City,
        user.State,
        userID,
    ); err != nil {
        return err
    }

    return nil
}

用户模型

type User struct {
    ID       uint64 `json:"id,omitempty"`
    Name     string `json:"name,omitempty"`
    CPF      string `json:"cpf,omitempty"`
    Email    string `json:"email,omitempty"`
    Password string `json:"password,omitempty"`
    City     string `json:"city,omitempty"`
    State    string `json:"state,omitempty"`
}
英文:

I have an application in go, and there is an endpoint for editing user information. But I found a problem, if in json it sees blank information (let's assume the user just wants to edit the name, and leaves the other fields blank), the data will be edited in the DB and the information that came blank will overwrite the information that are DB, even if the user didn't want to edit them.

How can I make only the fields that arrive in json to be effectively edited in the DB? Or is there a better way?

I'm looking forward to knowing!

My controller

func EditUser(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
userID, err := strconv.ParseUint(params["userID"], 10, 64)
if err != nil {
returns.ERROR(w, http.StatusInternalServerError, err)
return
}
userIDInToken, err := auth.ExtractUserID(r)
if err != nil {
returns.ERROR(w, http.StatusInternalServerError, err)
return
}
if userIDInToken != userID {
returns.ERROR(w, http.StatusForbidden, errors.New("you can't update other user"))
return
}
bodyRequest, err := ioutil.ReadAll(r.Body)
if err != nil {
returns.ERROR(w, http.StatusBadRequest, err)
return
}
var user models.User
if err := json.Unmarshal(bodyRequest, &user); err != nil {
returns.ERROR(w, http.StatusUnprocessableEntity, err)
return
}
db, err := db.ConnectToDB()
if err != nil {
returns.ERROR(w, http.StatusInternalServerError, err)
return
}
defer db.Close()
repository := repositories.NewUsersRepository(db)
if err := repository.UpdateUserInfo(userID, user); err != nil {
returns.ERROR(w, http.StatusInternalServerError, err)
return
}
returns.JSON_RESPONSE(w, http.StatusOK, nil)
}

My repository (that access DB)

func (repository Users) UpdateUserInfo(userID uint64, user models.User) error {
stmt, err := repository.db.Prepare(
"UPDATE user SET name = ?, cpf = ?, email = ?, password = ?, city = ?, state = ? WHERE id = ?")
if err != nil {
return err
}
defer stmt.Close()
if _, err := stmt.Exec(
user.Name,
user.CPF,
user.Email,
user.Password,
user.City,
user.State,
userID,
); err != nil {
return err
}
return nil
}

Model for user

type User struct {
ID       uint64 `json:"id,omitempty"`
Name     string `json:"name,omitempty"`
CPF      string `json:"cpf,omitempty"`
Email    string `json:"email,omitempty"`
Password string `json:"password,omitempty"`
City     string `json:"city,omitempty"`
State    string `json:"state,omitempty"`
}

答案1

得分: 0

我会动态构建UPDATE语句,并通过检查字段是否为空来确定需要编辑的字段,并返回一个字段切片。

类似这样的代码:

func (repository Users) UpdateUserInfo(userID uint64, user User) error {
	fields := make([]string, 0)
	values := make([]string, 0)

	if user.Name != "" {
		values = append(values, user.Name)
		fields = append(fields, "name = ?")
	}
	if user.CPF != "" {
		values = append(values, user.CPF)
		fields = append(fields, "cpf = ?")
	}
	if user.Email != "" {
		values = append(values, user.Email)
		fields = append(fields, "email = ?")
	}
	if user.Password != "" {
		values = append(values, user.Password)
		fields = append(fields, "password = ?")
	}
	if user.City != "" {
		values = append(values, user.City)
		fields = append(fields, "city = ?")
	}
	if user.State != "" {
		values = append(values, user.State)
		fields = append(fields, "state = ?")
	}

	if len(fields) == 0 {
		return errors.New("no fields to update")
	}

	updateString := fmt.Sprintf("UPDATE user SET %s WHERE id = ?", strings.Join(fields, ","))
	stmt, err := repository.db.Prepare(updateString)
	if err != nil {
		return err
	}
	defer stmt.Close()

	if _, err := stmt.Exec(append(values, userID)...); err != nil {
		return err
	}

	return nil
}

为了使代码更清晰,我建议将"if语句"和验证提取到一个单独的函数中。

英文:

I would dynamically construct the UPDATE statement as well as a slice of the fields that need to be edited by checking if the field is not empty before adding it to the slice.

Something like this:

func (repository Users) UpdateUserInfo(userID uint64, user User) error {
	fields := make([]string, 0)
	values := make([]string, 0)

	if user.Name != "" {
		values = append(values, user.Name)
		fields = append(fields, "name = ?")
	}
	if user.CPF != "" {
		values = append(values, user.CPF)
		fields = append(fields, "cpf = ?")
	}
	if user.Email != "" {
		values = append(values, user.Email)
		fields = append(fields, "email = ?")
	}
	if user.Password != "" {
		values = append(values, user.Password)
		fields = append(fields, "password = ?")
	}
	if user.City != "" {
		values = append(values, user.City)
		fields = append(fields, "city = ?")
	}
	if user.State != "" {
		values = append(values, user.State)
		fields = append(fields, "state = ?")
	}

	if len(fields) != 0 {
		return errors.New("no fields to update")
	}

	updateString := fmt.Sprintf("UPDATE user SET %s WHERE id = ?", strings.Join(fields, ","))
	stmt, err := repository.db.Prepare(updateString)
	if err != nil {
		return err
	}
	defer stmt.Close()

	if _, err := stmt.Exec(values...,userID); err != nil {
		return err
	}

	return nil
}

For cleaner code, I'd recommend maybe extracting the "if statements"/validation into a separate function.

huangapple
  • 本文由 发表于 2021年9月22日 02:26:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/69273869.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定