【问题标题】:JPA EntityManager - Using merge to generate default value?JPA EntityManager - 使用合并生成默认值?
【发布时间】:2017-02-22 20:43:04
【问题描述】:

我有一个 JPA 实体,它有一个创建日期和一个修改日期列。在创建/保留时,创建日期和修改日期均由数据库中给定的默认值生成,即时间戳。但是,当我尝试进行更新/合并时,创建工作有效,我无法弄清楚如何通过使用数据库中的默认值来更改修改日期。有什么建议吗?这是当前设置:

....
@Temporal(TemporalType.DATE)
@Column(name="CREATED_DATE", insertable = false, updatable = false)
private Date createdDate;

@Temporal(TemporalType.DATE)
@Column(name="MODIFIED_DATE", insertable = false)
private Date modifiedDate;
....

-

public Database changeDate(Database oldValues)
    Database newvalues = new Database();
    ....
    newValues.setCreatedDate(oldValues.getCreatedDate);
    //newValues.setModifiedDate(); <-- (Should use the default value in the database)
    ....
    em.merge(newValues); <-- (EntityManager)
    em.getTransaction().commit();

** 以防万一我没有说清楚,我只是不知道如何让它更新为数据库中设置的默认值。

【问题讨论】:

  • 只是为了让这一点更清楚一点,您是在说“我正在尝试将 newValues.modifiedDate 更新为新的 Date() 值,但在事务提交后,数据库显示没有更新”或“我正在尝试将 newValues.modifiedDate 更新为空值,但出现异常”?
  • 我想尝试让它更新到它存储在数据库中的默认值。将其设置为 null 没有帮助。我可能会使用新的 Date() 路由,但我仍然更喜欢默认值。
  • 我建议编辑您的问题并删除“null”。如果您改写您的问题以准确解释您想要做什么,我们将更容易提供帮助。
  • 编辑了问题。希望现在更清楚了。
  • newValuesnew Database() 实体,是吗?所以em.merge(newValues) 不是你应该做的。它需要坚持下去。 IOW:em.persist(newValues)

标签: java jpa entitymanager


【解决方案1】:

您想将 Null 值设置为日期。请在您的日期注释中添加可为空的属性。它会起作用的。

将其添加到您的注释中nullable = true

@Temporal(TemporalType.DATE)
@Column(name="CREATED_DATE",nullable = true, insertable = false, updatable = false)
private Date createdDate;

@Temporal(TemporalType.DATE)
@Column(name="MODIFIED_DATE", nullable = true, insertable = false)
private Date modifiedDate;

【讨论】:

  • 在数据库中,我将其设置为修改日期不能为空值的位置。使用注释,它只会给我同样的错误。 - 该值不能设置为空。我不认为我在我的问题中说得很清楚。很抱歉:c
【解决方案2】:

有一个注释你可以使用javax.persistence.Version

@Column(name="CREATED_DATE", updatable = false)
private java.sql.Timestamp createdDate = new java.sql.Timestamp(System.currentTimeMillis());

@Version
@Column(name="MODIFIED_DATE")
private java.sql.Timestamp modifiedDate;

两个字段只需要一个getter,不需要setter。 JPA 将自行比较和更新时间戳值。否则,如果您依赖数据库为您生成它,您不妨尝试@GeneratedValue(strategy = GenerationType.IDENTITY) 或 AUTO,但我很确定这在 Hibernate 中不起作用。也许它会在其他 JPA 提供者中工作。在 Hibernate 中,AUTO 的值始终回退到 SEQUENCE,因此该策略不可能奏效。

【讨论】:

  • 这个非常接近 - 唯一的问题是 GeneratedValue 注释已经被用于 ID,显然每个实体只能有一个(也许我应该从一开始就说,但我认为这没什么大不了的)。并且版本不允许使用 Date 类型。我尝试使用 Timestamp 只是为了看看它是否可以工作,但是实体无法与数据库匹配。
  • 如果你从数据库中的值中截断微秒(实际上小于毫秒),@Version with Timestamp 应该可以工作。在我们迁移到 Java 8 并切换到 Instant 之前,这就是我们必须做的事情。
【解决方案3】:

如果我正确理解了这个问题,您需要确保 MODIFIED_DATE 列始终设置为 CURRENT_TIMESTAMP。然后,当数据库实体被更新并且它的其他字段被修改时,MODIFIED_DATE 列将被设置为 CURRENT_TIMESTAMP。

我假设您的数据库表看起来像这样:

CREATE TABLE Database (
    ID int NOT NULL,
    CREATED_DATE TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    MODIFIED_DATE TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)

您想要做的是向您的数据库实体类添加一个@PreUpdate 方法,并让它每次都将 modifiedDate 属性设置为一个新的 Date()。然后,每当对实体进行更新时,MODIFIED_DATE 列将设置为新日期!

这是一个例子:

@PreUpdate
protected void onUpdate() {
    modifiedDate = new Date();
}

尝试一个简单的例子,看看它是如何工作的:

em.getTransaction().begin();
Database db = new Database(1, "First Value");
em.persist(db);
em.getTransaction().commit();

em.getTransaction().begin();
Database db2 = em.find(Database.class, 1);
db2.setValue("New Value!");
em.getTransaction().commit();

【讨论】:

  • 所以基本上使用新的 Date() 路线 - 到目前为止,这似乎是我唯一的选择。 PreUpdate 是一个相当不错的功能,但不知道它存在。
  • @RaccoTaco 问题是使用数据库表的默认功能仅用于插入新行。如果您插入新行并且未能为具有默认值的列提供值,则使用默认值来防止该值为 NULL。在您的用例中,将值初始化为默认值后,如果不删除行并重新插入,则无法撤消。
  • 虽然这可能有效,但我警告不要这样做。总的来说,我认为将这个业务逻辑放在数据库上是一个糟糕的设计决策。此外,我的回答为管理您的价值提供了更大的灵活性。依赖提供者或数据库设置值意味着手动更改值是不可能或困难的
猜你喜欢
  • 1970-01-01
  • 2023-03-23
  • 2015-05-25
  • 2013-09-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多