【问题标题】:JPA ID Generation StrategyJPA ID 生成策略
【发布时间】:2011-02-22 18:00:04
【问题描述】:

我为 JPA 类定义了一个生成器:

<sequence-generator name="MY_SEQ" allocation-size="-1"
    sequence-name="MY_SEQ"
    initial-value="100000000" />

在某些情况下,我已经有一个实体的 ID,但是当我插入实体时,ID 是使用生成器生成的。

是否可以定义一个生成器,只在一个不存在时才生成一个 Id?

我使用 Hibernate 作为 JPA 提供程序。

谢谢

【问题讨论】:

  • 如果条目不存在,你怎么已经有了ID。实施您所说的内容是个坏主意。
  • 我有 2 个数据库。一个在服务器上,另一个在 PC 本地。我的想法是我将数据下载到 PC 上,这样我就可以“离线”工作 这包括将实体下载到 PC 上。在 PC 上使用我们的软件时,他们可以创建新实体。我需要新实体的序列,如果它已经有一个 ID,我想插入具有该 ID 的实体。

标签: java hibernate jpa


【解决方案1】:

我在 JPA 中找不到执行此操作的方法,因此我使用了 Hibernate EJB3 事件侦听器。我骑过saveWithGeneratedId 使用反射来检查实体是否有@Id 注释,然后检查该字段的值。如果它有一个值,那么我改为调用saveWithRequestedId。否则,我让它生成 ID。这很有效,因为如果我需要一个 ID,我仍然可以使用为 Hibernate 设置的序列。反射可能会增加开销,因此我可能会对其进行一些更改。我正在考虑在所有实体中使用getId()getPK() 方法,因此我不必搜索哪个字段是@Id

在我使用反射之前,我尝试调用 session.getIdentifier(entity) 来检查,但我得到了 TransientObjectException("The instance was not associated with this session")。我不知道如何在不先保存实体的情况下让实体进入会话,所以我放弃了。下面是我写的监听代码。

public class MergeListener extends org.hibernate.ejb.event.EJB3MergeEventListener
 {



    @Override
    protected Serializable saveWithGeneratedId(Object entity, String entityName, Object anything, EventSource source, boolean requiresImmediateIdAccess) {


        Integer id = null;


            Field[] declaredFields = entity.getClass().getDeclaredFields();

            for (Field field : declaredFields) {

                Id annotation = field.getAnnotation(javax.persistence.Id.class);

                if(annotation!=null) {


                    try {
                        Method method = entity.getClass().getMethod("get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1));
                        Object invoke = method.invoke(entity);

                       id = (Integer)invoke;


                    } catch (Exception ex) {
                      //something failed (method not found..etc) , keep going anyway
                    }

                    break;

                }
            }



       if(id == null ||
                id == 0) {
        return super.saveWithGeneratedId(entity, entityName, anything, source, requiresImmediateIdAccess);
        } else {

            return super.saveWithRequestedId(entity, id, entityName, anything, source);
        }
    }
}

然后我必须将侦听器添加到我的 persistence.xml

 <property name="hibernate.ejb.event.merge" value="my.package.MergeListener"/>

【讨论】:

    【解决方案2】:

    这不是一个好主意,序列用于代理键,在商业意义上没有意义,但向您保证,不会有重复,因此在插入时不会出错。

    【讨论】:

    • 我这样做是有原因的(请参阅我上面的评论)。我已经找到了一种避免与 PK 重复的方法。我想知道是否可以编写一个生成器,如果没有 PK,将使用序列,如果已经有 PK,则不使用它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-23
    • 2012-04-19
    • 1970-01-01
    • 2016-03-23
    • 2012-06-09
    • 1970-01-01
    • 2019-03-01
    相关资源
    最近更新 更多