0

我正在尝试使用dynamic-sql方法和sql-builder方法创建一个动态更新语句,但我只管理它让它适用于string数据类型。在构造更新语句时,我不确定如何“转换”为正确的数据类型。

我想要实现的是使用Map<String, Object>或实际的 pojo生成更新语句Post

Post看起来像这样

public class Post {
    private Integer id;
    private String title;
    private String body;
    private LocalDateTime createdAt;
    private String createdBy;
    private LocalDateTime updatedAt;
    private String updatedBy;
}

原因Map<String, Object>是为了更容易遍历集合并构造语句。使用 pojo 需要我使用reflection我尽量不使用的。

在了解我是如何做到的之前

这就是在 pojo 中使用普通更新语句时的样子

@PutMapping("/{id}")
public Post updateById(@PathVariable Integer id, @RequestBody Post post) {
    return this.postService.updateById(id, post);
}

@Update("UPDATE POST SET title = #{p.title}, body = #{p.body}, createdAt = #{p.createdAt}, createdBy = #{p.createdBy}, updatedAt = #{p.updatedAt}, updatedBy = #{p.updatedBy} WHERE id = #{id}")
public boolean updateById(@Param("id") Integer id, @Param("p") Post post);

这将导致

2021-10-30 12:03:15.037 DEBUG 15988 --- [nio-8080-exec-2] c.b.s.s.post.PostMapper.updateById       : ==>  Preparing: UPDATE POST SET title = ?, body = ?, createdAt = ?, createdBy = ?, updatedAt = ?, updatedBy = ? WHERE id = ?
2021-10-30 12:03:15.064 DEBUG 15988 --- [nio-8080-exec-2] c.b.s.s.post.PostMapper.updateById       : ==> Parameters: jsonpatch1(String), bo21(String), 2021-10-30T12:03:14.954483(LocalDateTime), stackoverflow(String), 2021-10-30T12:03:14.954483(LocalDateTime), stackoverflow(String), 65(Integer)

因此,我尝试这样做

// What this does is to strip off all the null values, and keep only those with value
// and convert into a map to pass and run in the dynamic sql later
@PatchMapping(path = "/{id}")
public Post patchById(@PathVariable Integer id, @RequestBody Post post) {
    ObjectMapper om = new ObjectMapper();
    om.setSerializationInclusion(Include.NON_NULL);
    om.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    om.registerModule(new JavaTimeModule());
    Map<String, Object> mp = om.convertValue(post, new TypeReference<Map<String, Object>>(){});
    return this.postService.patchById(id, mp);
}

它去哪里mapper看起来像这样

@Update({
    "<script>",
    "UPDATE POST",
    "<set>",
    "<foreach item='item' index='index' collection='p.entrySet()'>",
    "${index} = #{item},",
    "</foreach>",
    "</set>",
    "WHERE id = #{id}",
    "</script>"
})
public boolean update(@Param("id") Integer id, @Param("p") Map<String, Object> post);

如果所有值都是string. 但是,如果存在 的字段LocalDateTime createdAt,则该createdAt字段被视为string类型

021-10-30 15:21:27.666 DEBUG 12324 --- [nio-8080-exec-2] c.b.s.s.post.PostUpdateMapper.update     : ==>  Preparing: UPDATE POST SET createdAt = ?, title = ?, body = ? 
WHERE id = ?
2021-10-30 15:21:27.669 DEBUG 12324 --- [nio-8080-exec-2] c.b.s.s.post.PostUpdateMapper.update     : ==> Parameters: 2021-09-10T11:31:07.5306869(String), jsonpatch1(String), bo221(String), 65(Integer)

我相信,那是因为我将其切换到Map<String, Object>,因此类型 (LocalDateTime) 因转换而丢失。但是,如果我要使用 pojoBean

我会有这样的东西

@PatchMapping(path = "/{id}")
public Post patchById(@PathVariable Integer id, @RequestBody Post post) {
    return this.postService.patchById(id, post);
}

@UpdateProvider(type=SQLUpdate.class, method = "update")
public boolean update(Integer id, Post post);

// just a poc to see if it works
public String update(Integer id, Post post) throws IllegalArgumentException, IllegalAccessException {
    Field[] f = post.getClass().getDeclaredFields();
    return new SQL() {{
        UPDATE("POST");
        for(Field field: f) {
            field.setAccessible(true);
            if (field.get(post) != null) {
                SET(field.getName() + " = '" + field.get(post) + "'");
            }
        }
        WHERE("id = " + id);
    }}.toString();
}

所以无论哪种方式,我都不确定如何传入正确的类型,以便它可以拦截并正确运行


如果我能做到这一点,这将是更理想的解决方案

@Update({
    "<script>",
    "UPDATE POST",
    "<set>",
    // being able to check if the value is null and set the field and value dynamically
    "<if test='#{p.value} != null>p.fieldname = #{p.value}",
    "</set>",
    "WHERE id = #{id}",
    "</script>"
})
public boolean update(@Param("id") Integer id, @Param("p") Post post);

让我知道是否需要更多信息,或者是否有更好的方法来实现我想做的事情

谢谢!

PS:我知道并且我得到它与mybatis-dynamic-sql lib 一起使用,但有兴趣知道它是否可以在不使用 lib 的情况下工作

4

0 回答 0