hibernate 中是否有设置在保存 hibernate 对象时忽略属性的空值?
注意
就我而言,我通过 Jackson 将 JSON 反序列化为 Hibernate Pojo。
JSON仅包含Pojo的部分字段。如果我保存 Pojo,则不在 JSON 中的字段在 Pojo 中为空,并且 hibernate 会更新它们。
我遇到了设置
updateable=false
,但这不是100%的解决方案。
http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#entity-mapping-property
也许有人有另一个想法......
注2:
根据 Hibernate 文档,
dynamicUpdate
注释正是这样做的
http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html_single/#mapping-declaration-class动态插入/动态更新(默认为 false):
指定应在运行时生成 INSERT / UPDATE SQL 并且仅包含值不为空的列。
dynamic-update
在 XML 中定义它,那就足够有趣了,文档中没有提到 NULL 值的处理。
dynamic-update(可选 - 默认为 false):
指定 UPDATE SQL 应在运行时生成,并且只能包含那些值已更改的列。AND由于我同时使用注释
xml 配置,hibernate 似乎忽略了我的 dynamicUpdate=true
注释。
hibernate 无法确定值为 null 的属性是否已显式设置为该值或已被排除。
如果是插入,则dynamic-insert=true 应该可以工作。
public void setAccount(Account a) throws HibernateException {
try {
Account tmp = (Account) session.
get(Account.class, a.getAccountId());
tmp.setEmail(getNotNull(a.getEmail(), tmp.getEmail()));
...
tmp.setVersion(getNotNull(a.getVersion(), tmp.getVersion()));
session.beginTransaction();
session.update(tmp);
session.getTransaction().commit();
} catch (HibernateException e) {
logger.error(e.toString());
throw e;
}
}
public static <T> T getNotNull(T a, T b) {
return b != null && a != null && !a.equals(b) ? a : b;
}
我收到一个包含很多字段的
Object a
。这些字段可能是
null
,但我不想将它们更新到mysql中。
我从 db 获取一个 tmp Obejct
,并通过方法 getNotNull
更改字段,然后更新对象。中文说明版
public String getUpdateJPQL(Object obj, String column, Object value) throws JsonProcessingException, IOException {
//obj -> your entity class object
//column -> field name in the query clause
//value -> value of the field in the query clause
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(obj);
Map<String, Object> map = mapper.readValue(json, Map.class);
Map format = new HashMap();
if (value instanceof String) {
value = "'" + value + "'";
}
map.keySet()
.forEach((str) -> {
Object val = map.get(str);
if (val != null) {
format.put("t.".concat(str), "'" + val + "'");
}
});
String formatStr = format.toString();
formatStr = formatStr.substring(1, formatStr.length() - 1);
return "update " + obj.getClass()
.getSimpleName() + " t set " + formatStr + " where " + column + " = " + value + "";
}
示例:对于带有字段的实体类型
User
:
userId
、userName
和 userAge
; getUpdateJPQL(user, userId, 2)
的结果查询应该是update User t set t.userName = 'value1', t.userAge = 'value2' where t.userId = 2
请注意,您可以在 @JsonIgnore
字段上使用像 userId
这样的 json 注释,以将其排除在反序列化中,即在生成的查询中。
然后,您可以使用EntityManager或hibernate会话运行查询。DTO
@Data
public class ProductRequest {
private Optional<String> name;
private Optional<String> unitSale;
}
端点
@PUT
@Path("/{id}")
public Response update(@PathParam("id") Long productId, @NotNull ProductRequest productModel) {
productService.update(productId, productModel);
return Response.status(Status.ACCEPTED).build();
}
服务
@Transactional
public void update(Long productId, @Valid ProductRequest productRequest) {
ProductEntity productEntity = productRepository.findByIdOptional(productId)
.orElseThrow(() -> new EntityNotFoundException("Product ID not found"));
if (productRequest.getName() != null) {
productEntity.name = unwrapOptional(productRequest.getName());
}
if (productRequest.getUnitSale() != null) {
productEntity.unitSale = unwrapOptional(productRequest.getUnitSale());
}
}
public <T> T unwrapOptional(final Optional<T> o) {
return o.isPresent() ? o.get() : null;
}
秘密是在 DTO 类中使用Optional<>,因为它可以区分请求正文中的显式 null 与由于请求中省略参数而导致的 null。