【问题标题】:JPA @Version behaviourJPA @Version 行为
【发布时间】:2011-07-12 15:06:31
【问题描述】:

我在 Hibernate 3.6.x 中使用 JPA2

我对@Version做了一个简单的测试。

假设我们有 2 个实体,

  1. Entity Team 有一个 Player Entities 列表,双向关系,lazy fetchtype,cascade-type All
  2. 两个实体都有@Version

这里是场景:

  1. 每当对团队/玩家实体之一进行修改时,刷新/提交时团队/玩家的版本将增加(修改记录上的版本增加)。

  2. 使用persist将新的玩家实体添加到团队的集合中,将在persist后分配团队版本的实体(添加新实体,新实体将获得它的版本)。

  3. 每当对玩家实体之一进行添加/修改/删除时,刷新/提交时团队的版本将增加。 (添加/修改/删除子记录,父版本也增加了)

1号和2号我能看懂,但是3号我就不明白了,为什么团队的版本变高了?

这让我想到了其他问题:

  1. 如果我得到了父 子 孙关系船怎么办。对孙子的添加或修改会增加子代和父代的版本吗?
  2. 在场景号 2 中,我如何在团队提交之前获得版本,比如使用 flush ?在我们对孩子做了一些事情之后,是否推荐使用这种方式来获取父母的版本?

这是我实验的代码示例,证明当 ReceivingGoodDetail 是拥有方时,刷新后 ReceivingGood 中的版本增加了。抱歉,这使用了其他实体,但 ReceivingGood 就像 Team,ReceivingGoodDetail 就像 Player。 1 个 ReceivingGood/Team,许多 ReceivingGoodDetail/Player。

/*
Hibernate: select receivingg0_.id as id9_14_, receivingg0_.creationDate as creation2_9_14_, .. too long
Hibernate: select product0_.id as id0_4_, product0_.creationDate as creation2_0_4_, .. too long
before persisting the new detail, version of header is : 14
persisting the detail 1c9f81e1-8a49-4189-83f5-4484508e71a7
printing the size of the header : 
Hibernate: select details0_.receivinggood_id as receivi13_9_8_, details0_.id as id8_, details0_.id as id10_7_, .. too long
7
after persisting the new detail, version of header is : 14
Hibernate: insert into ReceivingGoodDetail (creationDate, modificationDate, usercreate_id, usermodify_id, version, buyQuantity, buyUnit, internalQuantity, internalUnit, product_id, receivinggood_id, supplierLotNumber, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: update ReceivingGood set creationDate=?, modificationDate=?, usercreate_id=?, usermodify_id=?, version=?, purchaseorder_id=?, supplier_id=?, transactionDate=?, transactionNumber=?, transactionType=?, transactionYearMonth=?, warehouse_id=? where id=? and version=?
after flushing, version of header is now : 15
    */
public void addDetailWithoutTouchingCollection() {
    String headerId = "3b373f6a-9cd1-4c9c-9d46-240de37f6b0f";
    ReceivingGood receivingGood = em.find(ReceivingGood.class, headerId);

    // create a new detail
    ReceivingGoodDetail receivingGoodDetailCumi = new ReceivingGoodDetail();
    receivingGoodDetailCumi.setBuyUnit("Drum");
    receivingGoodDetailCumi.setBuyQuantity(1L);
    receivingGoodDetailCumi.setInternalUnit("Liter");
    receivingGoodDetailCumi.setInternalQuantity(10L);
    receivingGoodDetailCumi.setProduct(getProduct("b3e83b2c-d27b-4572-bf8d-ac32f6de5eaa"));
    receivingGoodDetailCumi.setSupplierLotNumber("Supplier Lot 1");
    decorateEntity(receivingGoodDetailCumi, getUser("3978fee3-9690-4377-84bd-9fb05928a6fc"));
    receivingGoodDetailCumi.setReceivingGood(receivingGood);

    System.out.println("before persisting the new detail, version of header is : " + receivingGood.getVersion());

    // persist it
    System.out.println("persisting the detail " + receivingGoodDetailCumi.getId());
    em.persist(receivingGoodDetailCumi);

    System.out.println("printing the size of the header : ");
    System.out.println(receivingGood.getDetails().size());

    System.out.println("after persisting the new detail, version of header is : " + receivingGood.getVersion());

    em.flush();

    System.out.println("after flushing, version of header is now : " + receivingGood.getVersion());
}

【问题讨论】:

  • 关系的拥有方是哪一方?球员还是球队?
  • 我只是假设“拥有方”一词是指拥有实体集合的一方。 Team 与 Player 有一对多的关系。所以我认为这意味着团队是拥有方,因为它拥有一群球员。
  • 简而言之,拥有方是您主动更改的部分。基本上,“一个人有很多书”,而不是“一本书有很多人”。在您的情况下,“团队由玩家组成”。所以,你会改变一个球员的球队,而不是球队的球员(player.setTeam() 而不是 team.getPlayers()...setTeam())
  • 顺便说一句:axtavt 实际上回答了你的问题。我相信他也认为拥有方是玩家。
  • @partenon:谢谢你的解释。明天将在我的办公室电脑上再次检查我的测试代码。我的代码围绕着从EM中获取玩家实体,然后修改玩家实体中的一些属性,然后利用team.addPlayer(player),其主要过程基本上是删除集合中存在的玩家,并添加它又来收藏了,还设置了玩家的队伍。也许我真的不需要再次将其添加到列表中以避免团队记录中的版本增加,考虑到当我从 EM 获得玩家实体时,它已经被管理了。

标签: hibernate jpa jpa-2.0


【解决方案1】:

它看起来像 Hibernate 中的一个错误。

JPA 规范说:

实体拥有的所有非关系字段和属性以及所有关系 包含在版本检查中

但是,Hibernate 也会在更改非拥有关系属性后增加版本(而例如,EclipseLink 不会这样做)。可以通过在属性上设置 @OptimisticLock(exclude = true) 来禁用此行为。

注意,它只适用于关系属性本身的变化,不适用于被引用对象状态的变化,这样父的版本就不会因为孙子集合的变化而发生变化。

【讨论】:

  • @axtavt :很高兴知道这一点。您是否碰巧知道这是否已经报告给 Hibernate 团队?
  • @axtavt:“但是,Hibernate 也会在更改非拥有关系属性后增加版本”
  • @Albert: 如果Player 是拥有方,则不应增加Team 的版本,但如果Team 是拥有方则应该增加。这就是它的指定方式以及 EclipseLink 的工作方式。然而,Hibernate 在这两种情况下都会增加版本。
  • @partenon:我找不到。如果没有人能在这里提供更好的解释,我想我会报告它。
  • @axtavt:啊,我明白了。我认为在我的代码中,我调用 team.addPlayer(player) 基本上将玩家再次放入集合中,并将玩家的团队设置为团队的当前实例。也许这就是团队版本增加的原因,因为我们对它的玩家集合进行了一些操作?而玩家的版本也因为修改了记录而增加了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-02-04
  • 1970-01-01
  • 2014-08-24
  • 1970-01-01
  • 2010-12-22
  • 2015-05-31
  • 2015-10-28
相关资源
最近更新 更多