Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/hibernate/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Hibernate 复合键的JPA自动增量_Hibernate_Postgresql_Jpa - Fatal编程技术网

Hibernate 复合键的JPA自动增量

Hibernate 复合键的JPA自动增量,hibernate,postgresql,jpa,Hibernate,Postgresql,Jpa,假设我想建模一个问题跟踪者,我的模型由两个实体组成:存储库和问题。存储库可能包含几个问题。因此,您可以大致获得以下JPA类: @Entity @Table(name="repository") public class Repository { @Id @GeneratedValue private Integer id; private String name; // Getters and setters } 对于问题类: @Entity @

假设我想建模一个问题跟踪者,我的模型由两个实体组成:存储库和问题。存储库可能包含几个问题。因此,您可以大致获得以下JPA类:

@Entity
@Table(name="repository")
public class Repository {

    @Id
    @GeneratedValue 
    private Integer id;

    private String name;

    // Getters and setters
}
对于问题类:

@Entity
@Table(name="issue")
@IdClass(Issue.IssuePk)
public class Issue {

   static class IssuePk implements Serializable {

        private Repository repository;
        private Integer issueNumber;
        // Getters, setters, equals and hashcode

    }

    @Id
    @ManyToOne
    private Repository repository;

    @Id
    private Integer issueNumber;

    // Getters and setters
}
现在,我希望以类似于自动递增的方式生成问题编号,但随后生成存储库的本地编号。我看到了各种各样的选择,但我不确定什么是最好的

在实例化问题时手动计算Id 不使用任何自动生成,只是在持久化之前设置值。因此:查询存储库中的问题,计算最大问题数量(如果有),增加、设置并持久化。这让人感觉有点容易出错,因为若要实例化代码其他部分的问题,就需要记住这一点

Issue issue = new Issue();
issue.setRepository(repository);
// For example, assuming this is right for the context now:
issue.setIssueNumber(repository.getIssues().size() + 1);
(显然,可以重构此问题以消除此问题编号生成的重复数据,但这并不能防止
null
issueNumber问题在
EntityManger上被
持久化

JPA生命周期事件 使用JPA生命周期事件,挂接
@PrePersist
并在那里执行相同的操作。这样做的好处是它是自动调用的,并且不必在代码库中重复

// On the issue entity
@PrePersist
void setIssueNumberOnPersist() {
     if(getIssueNumber() == null) {
          setIssueNumber(getRepository().getIssues().size() + 1);
      }
}
然而,这似乎与JPA的一项限制相冲突:

为避免与触发实体生命周期事件(仍在进行中)的原始数据库操作发生冲突,回调方法不应调用EntityManager或查询方法,也不应访问任何其他实体对象

使用数据库触发器 通过issue表上的触发器设置issueId值,并让JPA在插入后更新其值。这种方法的一个缺点是,如果切换数据库,必须修补此触发器

我现在不太喜欢编写触发器,但我认为大致应该是:

before insert on issue
    select max(issue_id) as val from issue where repository = issue.repository
    issue_id = val + 1
end
或者使用缓存的值:

before insert on issue
    select next_issue_id as val from repository where id = issue.repository_id
    issue_id = val
    update repository set next_issue_id = val + 1 where id = issue.repository_id
end
使用Hibernate
IdentifierGenerator
似乎
标识生成器也可以完成此工作。然而,它需要通过查询与数据库交互,我认为这会破坏与不同数据库和模式更改的兼容性

 public class IssueIdGenerator implements IdentifierGenerator {

     public Serializable generate(SessionImplementor session, Object object)
             throws HibernateException {

         Connection connection = session.connection();
         try {

             PreparedStatement ps = connection
                     .prepareStatement("... query ...");
             // Calculate the next issueId
             return issueId;
         } catch (SQLException e) {
             log.error(e);
             throw new HibernateException(
                     "Unable to generate Stock Code Sequence");
         }
         return null;
     }
 }
我错过了一个选择 如果我错过了一个选择,我很高兴听到


最佳选项是什么?

另一个选项是缓存附加到存储库的问题数量

因此,您可以创建一个字段
issueCount
,该字段将通过从数据库获取金额在构造函数中初始化,然后在创建问题时相应地递增

请记住,这必须同步,因为您不希望以相同的id出现两个问题

根据各种stackoverflow问题和论坛帖子,这似乎是一个已知的问题,Hibernate建议开发人员在他们的项目中创建逻辑,而不是依赖Hibernate的
@GeneratedValue