【问题标题】:DTO entity mapping with hibernate @Version control使用休眠 @Version 控制的 DTO 实体映射
【发布时间】:2013-09-11 01:59:13
【问题描述】:

我正在使用@Version 注释在休眠中提供版本控制。我的问题是关于从 DTO 到实体的数据的正确映射。 我觉得正确的方法如下,但我想知道是否有更好的方法或者每个人都是这样做的。

  • 来电为我服务
  • 我加载要更新的实体(假设 AddressEntity 版本 = 1)
  • 我将 AddressDTO 值映射到 AE,包括子集合(如果有)
  • 全部映射后,我分离实体 AE(仅在映射惰性子集合后分离)
  • 现在我将版本从 DTO 映射到 AE(因为休眠不允许更新托管实体中的版本)
  • 现在我调用 merge 来更新这个分离的 AE 实体

1) 这是正确的语义和逻辑方式吗?

2)(有点脱离上下文)休眠是否存在合并已经在上下文中和托管的对象的开销,即我可以安全地对所有更新使用合并,无论是托管/非托管还是仅合并+刷新用于非托管和刷新更新一些属性后管理?

【问题讨论】:

    标签: java hibernate jpa


    【解决方案1】:

    让我逐步回答你的问题:

    1. 假设您加载了AddressEntity (having id=123 and version=1)。将属性值从AddressEntity 设置为AddreeDto,包括idversion 值。将AddressDto 发送到 UI。
    2. AddresDto 所做的更改。电话已为您服务。创建AddressEntity 的实例并设置来自AddressDto 的值,包括idversion 值。这个新的AddressEntity 现在已经变成了一个分离的实例,因为它有一个持久的身份,但它的状态不能保证与数据库状态同步。
    3. Hibernate 允许您通过将这个Addressentity 实例与新的持久性管理器重新关联来在新事务中重用它。这个分离的实例可以通过调用 update() 与新的 Session 重新关联。您无需再次加载实体。update() 方法强制更新数据库中对象的持久状态。

      设置addressEntity属性:

      addressEntity.setId(dto.getId()); addressEntity.setVersion(dto.getVersion());

      addressEntity 附加到新会话:

      交易 tx = sessionTwo.beginTransaction(); sessionTwo.update(addressEntity);

      tx.commit(); sessionTwo.close();

    4. session.update 将执行类似这样的 SQL:

      更新 ADDRESS_ENTITY 设置 ... , VERSION=2 其中 ID=123 和 VERSION=1

    5. 如果另一个应用程序事务在加载后更新了相同的 ADDRESS_ENTITY,则 VERSION 列将不包含值 1,并且不会更新该行,您将收到 stale object state exception。您可以捕获异常并通知用户有关过时的数据。

    【讨论】:

      【解决方案2】:
      • 全部映射后,我分离实体 AE(仅在映射惰性子集合后分离)

      假设您在单个事务中执行此操作。您从 DB 检索到的任何持久对象都与当前会话和事务上下文相关联。如果在同一个事务中被修改,它的状态会自动与数据库同步。这种机制称为automatic dirty checking。这意味着 Hibernate 将跟踪并保存对会话内对象所做的更改。

      Transaction tx = session.beginTransaction();
      int addressEntityID = 1234;
      AddressEntity addressEntity = (AddressEntity) session.get(AddressEntity.class, new Long(addressEntityID));
      
      // set the values from AddressDTO to AddressEntity
      tx.commit();
      session.close();
      

      从数据库中检索对象,对其进行修改,并在事务提交时将修改传播到数据库。您无需分离和重新附加实体即可执行更新。

      • 现在我将版本从 DTO 映射到 AE(因为休眠不允许更新托管实体中的版本)

      托管版本控制用于实现乐观锁定,实体的版本控制由 Hibernate 管理。版本号只是一个计数器值,它没有任何有用的信息,你应该保留在你的 DTO 中。你不需要自己设置版本的值。 Hibernate 将在您第一次保存 AddressEntity 时初始化该值,并在修改对象时递增或重置它。

      如果另一个应用程序事务 (T2) 更新持久实例相同的项目,因为它被当前应用程序事务 (T1) 读取,T2 事务将更改此实体的版本值。现在,当 T1 尝试进行更新时,Hibernate 将抛出 stale object state exception,因为实体的 version 已更改。您可以捕获exception 并通知用户有关陈旧数据的信息。特别是,版本控制可以防止丢失更新问题。您无需将版本从 DTO 映射到 AE 或从 AE 映射到 DTO,因为它没有任何有意义的信息可用于实现乐观锁定以外的上下文。

      【讨论】:

      • 你还没明白我想问什么。我知道你所指定的一切。 hibernate 不允许显式设置版本。拿这个例子来说,我得到了 AE v=1,发送给 ui,ui 更新了一些字段,我把它拿回来了,这一次,别人更新了 AE v=2,现在我的 DTO 必须知道以前的版本是什么。所以我用 v=1 取回它,尝试映射它 n 更新 n 获取陈旧的对象,因为 DTO,实体有 v=1 并且 DB 有 v=2 !我的问题是关于映射 n 更新实体的过程
      • 是的..我可能误解了你的问题。让我尝试通过添加一个单独的答案来回答您的问题。
      猜你喜欢
      • 1970-01-01
      • 2019-12-03
      • 2020-12-18
      • 2016-02-14
      • 2016-10-18
      • 1970-01-01
      • 2021-11-11
      • 2015-10-31
      • 2015-11-25
      相关资源
      最近更新 更多