如何防止 Hibernate 更新 NULL 值

问题描述 投票:0回答:4

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
注释正是这样做的

动态插入/动态更新(默认为 false):
指定应在运行时生成 INSERT / UPDATE SQL 并且仅包含值不为空的列。

http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html_single/#mapping-declaration-class

如果您通过

dynamic-update

在 XML 中定义它,那就足够有趣了,文档中没有提到 NULL 值的处理。


dynamic-update(可选 - 默认为 false):
指定 UPDATE SQL 应在运行时生成,并且只能包含那些值已更改的列。


由于我同时使用注释
AND

xml 配置,hibernate 似乎忽略了我的 dynamicUpdate=true 注释。

    

hibernate null hibernate-mapping hibernate-annotations
4个回答
15
投票

hibernate 无法确定值为 null 的属性是否已显式设置为该值或已被排除。

如果是插入,则dynamic-insert=true 应该可以工作。


0
投票

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
更改字段,然后更新对象。

中文说明版


0
投票

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会话运行查询。
    


0
投票

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。

© www.soinside.com 2019 - 2024. All rights reserved.