How to implement IdentifierGenerator with PREFIX and separate Sequence for each entity

删除回忆录丶 提交于 2019-12-31 01:51:07

问题


I have followed basic Vlad's guide to implement prefixed generator, but haveing trouldles.

The goal is to simultaneously have:

  1. Separate sequence per each entity
  2. Prefix which I define via annotation (@GenericGenerator I guess)
  3. All sequences are dropped and created on each app restart (redeploy, whatever..) with hibernate.hbm2ddl.auto=create.
  4. Being able to set the prefix on PACKAGE level not only on class / id-field

How to implement those conditions simultaneously ?

THE (PARTIAL!) SOLUTION

I managed to solve the task partually with this:

@GenericGenerator(
    name = "prefix-sequence",
    strategy = "soberich.utils.StringSequenceIdentifier",
    parameters = {
            @Parameter(name="prefer_sequence_per_entity", value="true"),
            @Parameter(name = SEQUENCE_PREFIX, value = "A-")})

on each class / id-field

and the snippet below as implemented Generator Strategy.

import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.Session;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.id.Configurable;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.Type;

import javax.persistence.PersistenceException;
import java.io.Serializable;
import java.util.Properties;

import static java.lang.String.format;
import static java.lang.String.join;
import static org.hibernate.id.enhanced.SequenceStyleGenerator.*;
import static org.hibernate.internal.util.config.ConfigurationHelper.*;

public class StringSequenceIdentifier implements IdentifierGenerator, Configurable {
    public static final String SEQUENCE_PREFIX = "sequence_prefix"; 
    private String sequencePrefix;
    private String sequenceCallSyntax;
    @Override
    public void configure(final Type type,
                          final Properties params,
                          final ServiceRegistry serviceRegistry) throws MappingException {
        final JdbcEnvironment jdbcEnvironment = serviceRegistry.getService(JdbcEnvironment.class);
        final Dialect dialect = jdbcEnvironment.getDialect();
        sequencePrefix = getString(SEQUENCE_PREFIX, params, "SEQ_");
        final String sequencePerEntitySuffix =
                getString(CONFIG_SEQUENCE_PER_ENTITY_SUFFIX, params, DEF_SEQUENCE_SUFFIX);
        final String defaultSequenceName =
                getBoolean(CONFIG_PREFER_SEQUENCE_PER_ENTITY, params, false)
                        ? params.getProperty(JPA_ENTITY_NAME) + sequencePerEntitySuffix
                        : DEF_SEQUENCE_NAME;
        sequenceCallSyntax =
                dialect.getSequenceNextValString(getString(SEQUENCE_PARAM, params, defaultSequenceName));
    }
    @Override
    public Serializable generate(final SharedSessionContractImplementor session,
                                 final Object object) throws HibernateException {
        final long seqValue = ((Number) Session.class.cast(session)
                .createNativeQuery(sequenceCallSyntax)
                .uniqueResult()).longValue();
        return sequencePrefix + format("%011d", seqValue);
    }
}

PROBLEMS LEFT

  1. Wrong sequences created and dropped. System creates sequences with names

"Entity_SEQ" - generated automatically

and drops them after restart, BUT

entity_seq - lowercased sequences are the real ones which used for nextval('entity_seq'). So you should create them manually, overwise during restart while drop phase exception would be thrown like "..relation "entity_seq" does not exist". So, basicaly it does not work automatically. You have to create sequences!

It feels like there should be quite simple solution for that one.

  1. So, despite this solution kinda works (even though "buggy") PACKAGE level annotation does not work. It tries to create a sequence with the name "prefix-sequence" which is the name on the @GenericGenerator. Exactly same happens if instead @Parameter(name="prefer_sequence_per_entity", value="true") I put @Parameter(name = "sequence_name", value = "entity_seq") on class / id-field which I does not understand why.

来源:https://stackoverflow.com/questions/48736782/how-to-implement-identifiergenerator-with-prefix-and-separate-sequence-for-each

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!