【问题标题】:@Id @GeneratedValue but set own ID value@Id @GeneratedValue 但设置自己的 ID 值
【发布时间】:2011-01-07 16:01:56
【问题描述】:

我有一个生成 id 的表,但在某些情况下我想自己设置它。我可以以某种方式强制 Hibernate 忽略 @GeneratedValue 吗?

【问题讨论】:

  • 你试过了吗,看看会发生什么?
  • 是的,Hibernate 不关心是否设置了 id - 无论如何都会生成一个值。
  • 我知道我以前在某个地方见过这个:stackoverflow.com/questions/89439/… - 使用merge() 而不是persist()
  • 别忘了说 entity=merge(entity)。返回的实体是托管实体;原来的那个仍然无人管理。
  • 这似乎对我不起作用,我的实体仍然得到一个生成的 id,虽然我使用了合并

标签: java hibernate jpa


【解决方案1】:

这可能有点矫枉过正,但您是否考虑过编写自己的 CustomIDGenerator,它可能子类说 Hibernate 的 AutoGenerator 并公开了几个方法,您可以在其中设置要生成的下一个类对象的 id,例如

class MyGenerator extends .... {

public void setIdForObject(Class clazz, Long id) {
    //once you use this API, the next time an object of 
    //type clazz is saved the id is used
}

public void setIdForObject(Class clazz, Long id, Matcher matcher) {
    //once you use this API, the next time an object of 
    //type clazz is saved and the matcher matches yes the id will be 
    //assigned. Your matcher can match properties like name, age etc
    //to say the matched object
}
}

这可能会变得复杂,但至少按照hibernate doco 是可能的

【讨论】:

  • 在 hibernate.org 论坛上,有一个用户为这个确切的场景编写了他的生成器类:forum.hibernate.org/viewtopic.php?p=2404032
  • 我偶然发现了这个请求,正在寻找完全相同问题的解决方案(尽管我使用的是 EclipseLink 而不是休眠)。我开始使用自定义 ID 生成器,但是(至少在我的 EclipseLink 场景中)存在一个问题:我如何知道需要持久化的对象是否已经有 ID?我手头的自定义 ID 生成器中没有实体对象。所以我无法确定是否需要生成一个新 ID - 以防对象没有一个。或者,如果我只是返回对象已经拥有的 id(或者可能为 null 或任何必要的)。
  • 我之前评论的补充:在 EclipseLink 中,当创建自己的序列生成器时,有一个名为 shouldAlwaysOverrideExistingValue 的方法可以被覆盖。这似乎是一个可能的解决方案。尽管覆盖我没有完全监督的事情感觉有点不舒服,而且除了这个 bug 条目之外,也没有找到任何文档。
【解决方案2】:

虽然这个问题是很久以前提出的,但我在@lOranger 的this post 中找到了完美的答案,并想分享它。

此提案检查对象的当前 id 是否设置为 null 以外的其他值,如果是,则使用它,否则,使用默认(或配置的)生成策略生成它。

这很简单,直截了当,解决了@Jens 提出的问题,即无法检索对象的当前 ID。

我刚刚实现了它(通过扩展 UUIDGenerator),它就像一个魅力:-D

【讨论】:

    【解决方案3】:

    创建您自己的标识符生成器/序列生成器

    public class FilterIdentifierGenerator extends IdentityGenerator implements IdentifierGenerator{
    
    @Override
    public Serializable generate(SessionImplementor session, Object object)
            throws HibernateException {
        // TODO Auto-generated method stub
        Serializable id = session.getEntityPersister(null, object)
                .getClassMetadata().getIdentifier(object, session);
        return id != null ? id : super.generate(session, object);
    }
    
    }
    

    将您的实体修改为:

    @Id
    @GeneratedValue(generator="myGenerator")
    @GenericGenerator(name="myGenerator", strategy="package.FilterIdentifierGenerator")
    @Column(unique=true, nullable=false)
    private int id;
    ...
    

    在保存而不是使用persist() 时使用merge()update()

    【讨论】:

      【解决方案4】:

      对于您的用例,您可以手动添加此无用户。 一种方法是将插入操作放在名为“./import.sql”的文件上(在您的类路径中)。 当 SessionFactory 启动时,Hibernate 会去执行这些语句。

      【讨论】:

      • @Emmanuel Bernard 他说:但是,在某些情况下,我想自己设置。如果你定义了 Hibernate 应该如何保存一个实体(通过“/.import.sql”文件),那么它的标识符自动生成将不起作用,不是吗?
      • 不,这无关紧要,import.sql 是纯 SQL,因此您可以做任何您想做的事情,包括在需要时更新序列或表 ID
      • 很高兴知道 (+1) 我会试试的。
      猜你喜欢
      • 2012-02-23
      • 2016-11-27
      • 2012-11-11
      • 2021-09-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多