1

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

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

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

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

4

2 回答 2

3

让我尝试逐步回答您的问题:

  1. 假设您加载了一个AddressEntity (having id=123 and version=1). 将属性值设置为从AddressEntityAddreeDto包括idversion值。发送AddressDto到 UI。
  2. AddresDto. 电话已为您服务。创建一个实例AddressEntity并设置AddressDto包含id和值的version值。这个新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 set ... , VERSION=2 where ID=123 and VERSION=1

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

于 2013-09-11T05:39:05.853 回答
0
  • 在所有映射之后,我分离实体 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,因为除了实现乐观锁定之外,它没有任何可用于上下文的有意义的信息。

于 2013-09-11T03:25:20.090 回答