一个实体在PostgreSQL中有多个Hibernate序列生成器

4

我可以在一个实体中使用多个序列生成器吗,例如

@Id
@SequenceGenerator(name=”subscription_id_seq”,sequenceName=”subscription_id_seq”, allocationSize=7)
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator=”subscription_id_seq”)
@Column(unique=true, nullable=false)
private Integer id

@Column(name="code", nullable=false, unique=true )
@SequenceGenerator(name="subscription_code_1_seq",sequenceName="subscription_code_1_seq", allocationSize=7)
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="subscription_code_1_seq")
private Integer code;
3个回答

8

不可以。生成器仅适用于标识列。

请确保使用脚本(例如hibernate.hbm2ddl.import_files)创建此序列:

create sequence subscription_code_1_seq start 1 increment 7

然后使用以下这样的映射:

@Id
@SequenceGenerator(
        name="subscription_id_seq",
        sequenceName="subscription_id_seq",
        allocationSize=7
)
@GeneratedValue(
        strategy=GenerationType.SEQUENCE,
        generator="subscription_id_seq"
)
@Column(unique=true, nullable=false)
private Integer id;

@Column(
        name="code",
        nullable=false,
        unique=true,
        insertable = false,
        updatable = false,
        columnDefinition = "BIGINT DEFAULT nextval('subscription_code_1_seq')"
)
@Generated(GenerationTime.INSERT)
private Integer code;

我很高兴能够帮助。 - Vlad Mihalcea

4
简而言之,您可以为一个实体使用多个序列生成器,但仅限于主键(复合主键)。
从SequenceGenerator文档中得知:
定义了一个主键生成器,可以在GeneratedValue注释的生成器元素中引用该生成器名称。 序列生成器可以指定在实体类上或主键字段或属性上。 生成器名称的范围是持久性单元全局的(跨所有生成器类型)。
代码示例:
public class TestPK implements Serializable {

    private Integer test1;

    private Integer test2;

    ...
}

@Entity
@IdClass(TestPK.class)
public class Test implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @SequenceGenerator(name = "seq_test1", sequenceName = "seq_test1", allocationSize = 7)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_test1")
    @Column(name = "test1", unique = true, nullable = false)
    private Integer test1;

    @Id
    @Column(name = "test2", nullable = false, unique = true)
    @SequenceGenerator(name = "seq_test2", sequenceName = "seq_test2", allocationSize = 7)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_test2")
    private Integer test2;

    ...

    @Override
    public String toString() {
        return "Test{" +
                "test1=" + test1 +
                ", test2=" + test2 +
                '}';
    }
}

public interface TestRepository extends Repository<Test, String> {

    Page<Test> findAll(Pageable pageable);

    void save(Test test);
}

@SpringBootApplication
public class Application implements CommandLineRunner {

    @Autowired
    private TestRepository testRepository;

    @Override
    public void run(String... args) throws Exception {
        testRepository.save(new Test());
        Page<Test> all = testRepository.findAll(null);
        System.out.println(all.iterator().next());
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

0
另一种解决方案是使用@GeneratorType注释。通过此注释,您可以在插入和更新托管实体时提供自定义实现。在这种情况下,添加一个序列。
首先创建此序列,并在创建或更改表时添加它:
CREATE SEQUENCE project_code_seq INCREMENT 1 START 1;
ALTER TABLE project
    ADD COLUMN key bigint NOT NULL DEFAULT nextval('project_code_seq');

创建一个实现ValueGenerator接口的类:
public class ProjectCodeGenerator implements ValueGenerator<Long> {

    private static final String SELECT_NEXTVAL = "select nextval('project_code_seq')";

    @Override
    public Long generateValue(Session session, Object object) {
        if (object instanceof ProjectEntity project) {

                var result = (BigInteger) session.createNativeQuery(SELECT_NEXTVAL)
                        .setHibernateFlushMode(
                                FlushMode.COMMIT).getSingleResult();
                return result.longValue();
                
        } else {
            throw new RuntimeException("Can only be used for " + ProjectEntity.class);
        }
    }

}

然后在实体上,您可以添加@GeneratorType注释:

@GeneratorType(type = ProjectCodeGenerator.class, when = GenerationTime.INSERT)
private Long code;

请注意,ProjectCodeGenerator可以根据您的需求进行调整,并且可以添加更多的逻辑。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接