Closed li362692680 closed 1 year ago
可以自己实现,虽然实现比较容易,但是暂时不考虑添加到mapper中,你可以使用下面的实现。
实现代码如下,定义通用接口:
@Lang(Caching.class)
@UpdateProvider(type = MyExampleProvider.class, method = "updateFieldByExample")
<T, R> int updateFieldByExample(@Param("column") Fn<T, R> column, @Param("value") R value, @Param("example") Example<T> example);
在 MyExampleProvider
中实现 updateFieldByExample
方法:
public static String updateFieldByExample(ProviderContext providerContext) {
return SqlScript.caching(providerContext, new SqlScript() {
@Override
public String getSql(EntityTable entity) {
return ifTest("example.startSql != null and example.startSql != ''", () -> "${example.startSql}")
+ "UPDATE " + entity.table()
+ set(() -> "${column.toColumn()} = #{value}")
+ variableNotNull("example", "Example cannot be null")
//是否允许空条件,默认允许,允许时不检查查询条件
+ (entity.getProp("updateByExample.allowEmpty", true) ?
"" : variableIsFalse("example.isEmpty()", "Example Criteria cannot be empty"))
+ ExampleProvider.UPDATE_BY_EXAMPLE_WHERE_CLAUSE
+ ifTest("example.endSql != null and example.endSql != ''", () -> "${example.endSql}");
}
});
}
你可以对比上面的方法和 在
ExampleProvider
中的updateByExample
方法,就是简单改了改set()
中的内容,参考现有功能扩展很容易,理解里面写法后可以更灵活。
用法:
@Test
public void testUpdateByExample() {
SqlSession sqlSession = getSqlSession();
try {
ExampleMapper<User, Example<User>> exampleMapper = sqlSession.getMapper(UserMapper.class);
Example<User> example = new Example();
example.createCriteria().andEqualTo(User::getId, 1L);
//userName字段对应的列为name
Assert.assertEquals(1, exampleMapper.updateFieldByExample(User::getUserName, "测试", example));
sqlSession.rollback();
} finally {
//不要忘记关闭sqlSession
sqlSession.close();
}
}
执行的SQL:
DEBUG [main] - ==> Preparing: UPDATE user SET name = ? WHERE ( id = ? )
DEBUG [main] - ==> Parameters: 测试(String), 1(Long)
DEBUG [main] - <== Updates: 1
可以自己实现,虽然实现比较容易,但是暂时不考虑添加到mapper中,你可以使用下面的实现。
实现代码如下,定义通用接口:
@Lang(Caching.class) @UpdateProvider(type = MyExampleProvider.class, method = "updateFieldByExample") <T, R> int updateFieldByExample(@Param("column") Fn<T, R> column, @Param("value") R value, @Param("example") Example<T> example);
在
MyExampleProvider
中实现updateFieldByExample
方法:public static String updateFieldByExample(ProviderContext providerContext) { return SqlScript.caching(providerContext, new SqlScript() { @Override public String getSql(EntityTable entity) { return ifTest("example.startSql != null and example.startSql != ''", () -> "${example.startSql}") + "UPDATE " + entity.table() + set(() -> "${column.toColumn()} = #{value}") + variableNotNull("example", "Example cannot be null") //是否允许空条件,默认允许,允许时不检查查询条件 + (entity.getProp("updateByExample.allowEmpty", true) ? "" : variableIsFalse("example.isEmpty()", "Example Criteria cannot be empty")) + ExampleProvider.UPDATE_BY_EXAMPLE_WHERE_CLAUSE + ifTest("example.endSql != null and example.endSql != ''", () -> "${example.endSql}"); } }); }
你可以对比上面的方法和 在
ExampleProvider
中的updateByExample
方法,就是简单改了改set()
中的内容,参考现有功能扩展很容易,理解里面写法后可以更灵活。用法:
@Test public void testUpdateByExample() { SqlSession sqlSession = getSqlSession(); try { ExampleMapper<User, Example<User>> exampleMapper = sqlSession.getMapper(UserMapper.class); Example<User> example = new Example(); example.createCriteria().andEqualTo(User::getId, 1L); //userName字段对应的列为name Assert.assertEquals(1, exampleMapper.updateFieldByExample(User::getUserName, "测试", example)); sqlSession.rollback(); } finally { //不要忘记关闭sqlSession sqlSession.close(); } }
执行的SQL:
DEBUG [main] - ==> Preparing: UPDATE user SET name = ? WHERE ( id = ? ) DEBUG [main] - ==> Parameters: 测试(String), 1(Long) DEBUG [main] - <== Updates: 1
这个实现确实可以解决更新单个值的情况,多个值就不适用了,我自己实现了个example.updateEqualTo,但是需要修改Example源码,
public static String updateByExample(ProviderContext providerContext) {
return SqlScript.caching(providerContext, new SqlScript() {
@Override
public String getSql(EntityTable entity) {
return ifTest("example.startSql != null and example.startSql != ''", () -> "${example.startSql}")
+ "UPDATE " + entity.table()
+ set(() -> choose(() -> whenTest("example.updateCriterion != null and example.updateCriterion.size()>0", () -> UPDATE_BY_EXAMPLE_COLUMN)
+ otherwise(() -> entity.updateColumns().stream().map(column -> column.columnEqualsProperty("entity.")).collect(Collectors.joining(",")))))
//TODO 测试
+ variableNotNull("example", "Example cannot be null")
//是否允许空条件,默认允许,允许时不检查查询条件
+ (entity.getProp("updateByExample.allowEmpty", true) ?
"" : variableIsFalse("example.isEmpty()", "Example Criteria cannot be empty"))
+ UPDATE_BY_EXAMPLE_WHERE_CLAUSE
+ ifTest("example.endSql != null and example.endSql != ''", () -> "${example.endSql}");
}
});
}
public static final String UPDATE_BY_EXAMPLE_COLUMN =
" <foreach collection=\"example.updateCriterion\" item=\"criterion\"\n separator=\" , \">\n" +
" ${criterion.condition} #{criterion.value}\n" +
" </foreach>\n";
example = userAutoMapper.example();
example.updateEqualTo(UserAuto::getName, "测试名称").updateEqualTo(UserAuto::getId, 1).createCriteria().andEqualTo(UserAuto::getId, userAuto.getId());
Assert.assertEquals(1, userAutoMapper.updateByExample(null, example));
有什么好办法可以在不改源码的情况下实现我这个逻辑么??
多个值直接用实体。
即将发布的新版本可以更好的支持这个方法。
wrapper用法:
mapper.wrapper()
.set(User::getUserName, "弓长无忌")
.set(User::getSex, "M")
.eq(User::getUserName, "张无忌").update()
example用法:
Example<User> example = new Example();
example.createCriteria().andEqualTo(User::getId, 1L);
example.set(User::getUserName, "男主角").set(User::getSex, "M");
exampleMapper.updateByExampleSetValues(example);
如何实现根据Example更新单个字段的值?目前的更新需要传入实体对象