【问题标题】:Hibernate: @Column(updatable = false) not working for @MappedSuperclass休眠:@Column(updatable = false) 不适用于 @MappedSuperclass
【发布时间】:2020-12-29 10:46:39
【问题描述】:

我正在将 Spring Data JPA 与 Hibernate 一起使用,并且在 @Column 注释上的 updatable=false 属性方面遇到了问题。

我的所有 @Entity 对象都有一个基类,其 createdDate 定义如下:

@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
@Setter
@Getter
@ToString
public abstract class BaseEntity {

    @CreatedBy
    @Column(name = "CREATE_USER_ID", nullable = false, updatable = false)
    protected String createdBy;

    @CreationTimestamp
    @Column(name = "CREATE_TS", columnDefinition = "TIMESTAMP WITH TIME ZONE", nullable = false, updatable = false)
    protected Instant createdDate; //Audit for data use replication conflict resolution (Oracle Golden Gate)

    @LastModifiedBy
    @Column(name = "LAST_UPDATE_USER_ID")
    protected String lastModifiedBy;

    @UpdateTimestamp
    @Column(name = "LAST_UPDATE_TS", columnDefinition = "TIMESTAMP WITH TIME ZONE")
    protected Instant lastModifiedDate;

以下是我的子实体

@Entity
@Table(name = "CUSTOMER")
@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
@ToString(exclude = {""})
public class Customer extends BaseEntity 

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CUSTOMER_ID_SEQ")
    @SequenceGenerator(sequenceName = "Customer_ID_SEQ", allocationSize = 1, name = "CUSTOMER_ID_SEQ")
    @Column(name = "CUSTOMER_ID")
    private Long CustomerId;             //Primary identifier
    @Column(name = "CUSTOMER_NAME")
    private String customerName;        //Customer Name
    @Column(name = "COUNTRY")
    private String customerCountry;     //Customer Country
    @Column(name = "REGION")
    private String customerRegion;      //Customer Region

}

来自 CustomerService.java 的代码 sn-p

public CustomerDetails updateCustomer(CustomerDetails customerDetails, Long customerId) {
        Customer customer = customerEntityToDTOMapper.dtoToEntity(customerDetails);
        /**
            Some sort of business logic
        **/
        Customer updatedCustomer = customerRepository.saveAndFlush(customer);
        return customerEntityToDTOMapper.entityToDTO(updatedCustomer);
    }

现在,当我从邮递员调用 updateCustomer API 时,如果我更改请求正文中 createdDate 的值,它将在数据库中更新(数据库将用请求正文中传递的新值替换 createdDate 的实际值)。理想情况下,这不应该发生。无论我在 requestBody 中传递什么有效值,数据库中的 createdDate 都不应用于 updateCustomer API 调用。

同样在 createCustomer 请求中,如果 createdDate=null,JPA 将按照预期设置 createdDate,我会在 repository.saveAndFlush() 方法的响应中收到正确的日期。但是在 updateCustomer 中,如果我在实体中设置 createdDate=null,那么即使它存在于数据库中,createdDate 在 repository.saveAndFlush() 方法的响应中也会作为 null。

谁能帮我解决我哪里出错了?

【问题讨论】:

  • 您面临的异常是什么?
  • 你能发布你的 updateCustomer 方法的代码吗?
  • @BilboBaggins 我没有收到任何错误,但 saveAndFlush() 的行为和响应与预期不符
  • @solujic 添加了代码 sn-p
  • 好吧,如果您不想在更新时更改 createdDate,那么为什么要在请求正文中发送它?您可以从正文中省略该字段。

标签: java spring hibernate jpa spring-data-jpa


【解决方案1】:

处理@Column 注释属性以创建/更新/验证等模式并定义实体对表的约束(取决于 hbm2ddl.auto 属性)。

现在@persistenceContext 使用insertableupdatable 发出查询,如果未明确提供并设置为false,它将忽略查询中的字段。

由于在您的情况下,您没有提供代码,您是如何设置值的,我假设在update 的情况下,您将createdDate 设置为空,这将不起作用,因为您已经定义了该字段喜欢

 @CreationTimestamp // This will add the timestamp if null when entity is new only
    @Column(name = "CREATE_TS", columnDefinition = "TIMESTAMP WITH TIME ZONE", nullable = false, updatable = false)
    protected Instant createdDate; 

因此,您的更新将createdDate 显式更新为null,这将覆盖updatable=false 和AFAIK,updatable=false 存在一些奇怪的行为,它在实体中返回null(当您在保存后获取时)以及何时实体被再次保存,空值被持久化(无论updatable=false,它都会被保存,因为hibernate会看到该值被更改为null)

我建议删除 updatable=false 并仅使用 @CreationTimeStamp 属性,这不会更新值 See this 并且应该存在数据库约束以防止 null

【讨论】:

    【解决方案2】:

    具有讽刺意味的是,简单地删除“updatable = false”属性为我解决了这个问题。日期/时间戳在最初插入后不再更新。

    对于那些使用 .hbm.xml 文件的人:

    之前: <property name="createdOn" column="CREATED_ON" update="false"/>

    之后: <property name="createdOn" column="CREATED_ON"/>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-06-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多