问题
I have followed basic Vlad's guide to implement prefixed generator, but haveing trouldles.
The goal is to simultaneously have:
- Separate sequence per each entity
- Prefix which I define via annotation (
@GenericGenerator
I guess) - All sequences are dropped and created on each app restart (redeploy, whatever..) with
hibernate.hbm2ddl.auto=create
. - 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
- 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.
- 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