diff --git a/pom.xml b/pom.xml index 63dabe9dc..9091eeb91 100644 --- a/pom.xml +++ b/pom.xml @@ -87,7 +87,7 @@ io.ebean ebean-annotation - 6.8 + 6.9 diff --git a/src/main/java/io/ebean/config/dbplatform/IdType.java b/src/main/java/io/ebean/config/dbplatform/IdType.java index 1bb1fa432..90ee5fe24 100644 --- a/src/main/java/io/ebean/config/dbplatform/IdType.java +++ b/src/main/java/io/ebean/config/dbplatform/IdType.java @@ -35,6 +35,11 @@ public enum IdType { * Used when the key is a compound key or lookup table code. *

*/ - EXTERNAL + EXTERNAL, + + /** + * Auto mapping to platform preferred identity strategy. + */ + AUTO } diff --git a/src/main/java/io/ebean/plugin/BeanType.java b/src/main/java/io/ebean/plugin/BeanType.java index 45ee40995..81a77ef98 100644 --- a/src/main/java/io/ebean/plugin/BeanType.java +++ b/src/main/java/io/ebean/plugin/BeanType.java @@ -8,12 +8,11 @@ import io.ebean.event.BeanPersistListener; import io.ebean.event.BeanQueryAdapter; import io.ebeanservice.docstore.api.mapping.DocumentMapping; +import javax.annotation.Nonnull; import java.util.Collection; import java.util.List; import java.util.function.Consumer; -import javax.annotation.Nonnull; - /** * Information and methods on BeanDescriptors made available to plugins. */ @@ -156,11 +155,6 @@ public interface BeanType { */ IdType getIdType(); - /** - * Return the sequence name associated to this entity bean type (if there is one). - */ - String getSequenceName(); - /** * Return true if this bean type has doc store backing. */ diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdl.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdl.java index 6f7e09b37..4835c2deb 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdl.java +++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdl.java @@ -385,7 +385,7 @@ public class BaseTableDdl implements TableDdl { int allocate = toInt(createTable.getSequenceAllocate()); String seqName = explicitSequenceName; - if (seqName == null) { + if (seqName == null || seqName.isEmpty()) { seqName = namingConvention.getSequenceName(createTable.getName(), pk); } diff --git a/src/main/java/io/ebeaninternal/dbmigration/model/MTable.java b/src/main/java/io/ebeaninternal/dbmigration/model/MTable.java index db6a803a4..115f38ef6 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/model/MTable.java +++ b/src/main/java/io/ebeaninternal/dbmigration/model/MTable.java @@ -11,13 +11,14 @@ import io.ebeaninternal.dbmigration.migration.DropColumn; import io.ebeaninternal.dbmigration.migration.DropHistoryTable; import io.ebeaninternal.dbmigration.migration.DropTable; import io.ebeaninternal.dbmigration.migration.ForeignKey; -import io.ebeaninternal.dbmigration.migration.IdentityType; import io.ebeaninternal.dbmigration.migration.UniqueConstraint; +import io.ebeaninternal.server.deploy.BeanDescriptor; +import io.ebeaninternal.server.deploy.IdentityMode; +import io.ebeaninternal.server.deploy.BeanProperty; import io.ebeaninternal.server.deploy.PartitionMeta; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.math.BigInteger; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; @@ -27,6 +28,8 @@ import java.util.Map; import java.util.Set; import static io.ebeaninternal.dbmigration.ddlgeneration.platform.SplitColumns.split; +import static io.ebeaninternal.dbmigration.model.MTableIdentity.fromCreateTable; +import static io.ebeaninternal.dbmigration.model.MTableIdentity.toCreateTable; /** * Holds the logical model for a given Table and everything associated to it. @@ -84,18 +87,7 @@ public class MTable { */ private String indexTablespace; - /** - * If set then this overrides the platform default so for UUID generated values - * or DB's supporting both sequences and autoincrement. - */ - private IdentityType identityType; - - /** - * DB sequence name. - */ - private String sequenceName; - private int sequenceInitial; - private int sequenceAllocate; + private IdentityMode identityMode; /** * If set to true this table should has history support. @@ -130,6 +122,29 @@ public class MTable { private List droppedColumns = new ArrayList<>(); + public MTable(BeanDescriptor descriptor) { + this.name = descriptor.getBaseTable(); + this.identityMode = descriptor.getIdentityMode(); + this.storageEngine = descriptor.getStorageEngine(); + this.partitionMeta = descriptor.getPartitionMeta(); + this.comment = descriptor.getDbComment(); + if (descriptor.isHistorySupport()) { + withHistory = true; + BeanProperty whenCreated = descriptor.getWhenCreatedProperty(); + if (whenCreated != null) { + whenCreatedColumn = whenCreated.getDbColumn(); + } + } + } + + /** + * Construct for element collection or intersection table. + */ + public MTable(String name) { + this.name = name; + this.identityMode = IdentityMode.none(); + } + /** * Create a copy of this table structure as a 'draft' table. *

@@ -143,7 +158,7 @@ public class MTable { draftTable.whenCreatedColumn = whenCreatedColumn; // compoundKeys // compoundUniqueConstraints - draftTable.identityType = identityType; + draftTable.identityMode = identityMode; for (MColumn col : allColumns()) { draftTable.addColumn(col.copyForDraft()); @@ -164,9 +179,7 @@ public class MTable { this.indexTablespace = createTable.getIndexTablespace(); this.withHistory = Boolean.TRUE.equals(createTable.isWithHistory()); this.draft = Boolean.TRUE.equals(createTable.isDraft()); - this.sequenceName = createTable.getSequenceName(); - this.sequenceInitial = toInt(createTable.getSequenceInitial()); - this.sequenceAllocate = toInt(createTable.getSequenceAllocate()); + this.identityMode = fromCreateTable(createTable); List cols = createTable.getColumn(); for (Column column : cols) { addColumn(column); @@ -194,13 +207,6 @@ public class MTable { addForeignKey(foreignKey); } - /** - * Construct typically from EbeanServer meta data. - */ - public MTable(String name) { - this.name = name; - } - /** * Return the DropTable migration for this table. */ @@ -208,7 +214,7 @@ public class MTable { DropTable dropTable = new DropTable(); dropTable.setName(name); // we must add pk col name & sequence name, as we have to delete the sequence also. - if (identityType != IdentityType.GENERATOR && identityType != IdentityType.EXTERNAL) { + if (identityMode.isDatabaseIdentity()) { String pkCol = null; for (MColumn column : columns.values()) { if (column.isPrimaryKey()) { @@ -222,7 +228,7 @@ public class MTable { } if (pkCol != null) { dropTable.setSequenceCol(pkCol); - dropTable.setSequenceName(sequenceName); + dropTable.setSequenceName(identityMode.getSequenceName()); } } return dropTable; @@ -244,10 +250,7 @@ public class MTable { createTable.setStorageEngine(storageEngine); createTable.setTablespace(tablespace); createTable.setIndexTablespace(indexTablespace); - createTable.setSequenceName(sequenceName); - createTable.setSequenceInitial(toBigInteger(sequenceInitial)); - createTable.setSequenceAllocate(toBigInteger(sequenceAllocate)); - createTable.setIdentityType(identityType); + toCreateTable(identityMode, createTable); if (withHistory) { createTable.setWithHistory(Boolean.TRUE); } @@ -458,10 +461,6 @@ public class MTable { this.comment = comment; } - public void setStorageEngine(String storageEngine) { - this.storageEngine = storageEngine; - } - public String getTablespace() { return tablespace; } @@ -519,36 +518,10 @@ public class MTable { return compoundKeys; } - public void setSequenceName(String sequenceName) { - this.sequenceName = sequenceName; - } - - public void setSequenceInitial(int sequenceInitial) { - this.sequenceInitial = sequenceInitial; - } - - public void setSequenceAllocate(int sequenceAllocate) { - this.sequenceAllocate = sequenceAllocate; - } - - public void setWhenCreatedColumn(String whenCreatedColumn) { - this.whenCreatedColumn = whenCreatedColumn; - } - public String getWhenCreatedColumn() { return whenCreatedColumn; } - /** - * Set the identity type to use for this table. - *

- * If set then this overrides the platform default so for UUID generated values - * or DB's supporting both sequences and autoincrement. - */ - public void setIdentityType(IdentityType identityType) { - this.identityType = identityType; - } - /** * Return the list of columns that make the primary key. */ @@ -671,14 +644,6 @@ public class MTable { droppedColumns.add(columnName); } - private int toInt(BigInteger value) { - return (value == null) ? 0 : value.intValue(); - } - - private BigInteger toBigInteger(int value) { - return (value == 0) ? null : BigInteger.valueOf(value); - } - /** * Check if there are duplicate foreign keys. *

@@ -774,10 +739,6 @@ public class MTable { } } - public void setPartitionMeta(PartitionMeta partitionMeta) { - this.partitionMeta = partitionMeta; - } - /** * Clear foreign key as this element collection table logically references * back to multiple tables. diff --git a/src/main/java/io/ebeaninternal/dbmigration/model/MTableIdentity.java b/src/main/java/io/ebeaninternal/dbmigration/model/MTableIdentity.java new file mode 100644 index 000000000..932293870 --- /dev/null +++ b/src/main/java/io/ebeaninternal/dbmigration/model/MTableIdentity.java @@ -0,0 +1,91 @@ +package io.ebeaninternal.dbmigration.model; + +import io.ebean.annotation.IdentityGenerated; +import io.ebean.config.dbplatform.IdType; +import io.ebeaninternal.dbmigration.migration.CreateTable; +import io.ebeaninternal.dbmigration.migration.IdentityType; +import io.ebeaninternal.server.deploy.IdentityMode; + +import java.math.BigInteger; + +/** + * Helper to convert between IdentityMode and CreateTable + */ +class MTableIdentity { + + /** + * Return the IdentityMode from CreateTable. + */ + static IdentityMode fromCreateTable(CreateTable createTable) { + + IdType type = fromType(createTable.getIdentityType()); + int start = toInt(createTable.getSequenceInitial()); + int increment = toInt(createTable.getSequenceAllocate()); + String seqName = createTable.getSequenceName(); + + return new IdentityMode(type, IdentityGenerated.AUTO, start, increment, seqName); + } + + /** + * Set the IdentityMode to the CreateTable model. + */ + public static void toCreateTable(IdentityMode identityMode, CreateTable createTable) { + + if (!identityMode.isPlatformDefault()) { + createTable.setIdentityType(toType(identityMode.getIdType())); + } + final String seqName = identityMode.getSequenceName(); + if (seqName != null && !seqName.isEmpty()) { + createTable.setSequenceName(seqName); + } + + createTable.setSequenceInitial(toBigInteger(identityMode.getStart())); + createTable.setSequenceAllocate(toBigInteger(identityMode.getIncrement())); + } + + + private static IdType fromType(IdentityType type) { + if (type == null) { + return IdType.AUTO; + } + switch (type) { + case DEFAULT: + return IdType.AUTO; + case SEQUENCE: + return IdType.SEQUENCE; + case IDENTITY: + return IdType.IDENTITY; + case GENERATOR: + return IdType.GENERATOR; + case EXTERNAL: + return IdType.EXTERNAL; + } + return IdType.AUTO; + } + + private static IdentityType toType(IdType type) { + if (type == null) { + // intersection or element collection table + return null; + } + switch (type) { + case SEQUENCE: + return IdentityType.SEQUENCE; + case IDENTITY: + return IdentityType.IDENTITY; + case EXTERNAL: + return IdentityType.EXTERNAL; + case GENERATOR: + return IdentityType.GENERATOR; + } + return null; + } + + private static int toInt(BigInteger value) { + return (value == null) ? 0 : value.intValue(); + } + + private static BigInteger toBigInteger(int value) { + return (value == 0) ? null : BigInteger.valueOf(value); + } +} diff --git a/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildBeanVisitor.java b/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildBeanVisitor.java index 9b6e3147e..4bbc055e2 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildBeanVisitor.java +++ b/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildBeanVisitor.java @@ -1,13 +1,10 @@ package io.ebeaninternal.dbmigration.model.build; import io.ebean.config.dbplatform.DbPlatformType; -import io.ebean.config.dbplatform.IdType; -import io.ebeaninternal.dbmigration.migration.IdentityType; import io.ebeaninternal.dbmigration.model.MColumn; import io.ebeaninternal.dbmigration.model.MTable; import io.ebeaninternal.dbmigration.model.visitor.BeanVisitor; import io.ebeaninternal.server.deploy.BeanDescriptor; -import io.ebeaninternal.server.deploy.BeanProperty; import io.ebeaninternal.server.deploy.InheritInfo; /** @@ -35,19 +32,7 @@ public class ModelBuildBeanVisitor implements BeanVisitor { return null; } - MTable table = new MTable(descriptor.getBaseTable()); - table.setStorageEngine(descriptor.getStorageEngine()); - table.setPartitionMeta(descriptor.getPartitionMeta()); - table.setComment(descriptor.getDbComment()); - if (descriptor.isHistorySupport()) { - table.setWithHistory(true); - BeanProperty whenCreated = descriptor.getWhenCreatedProperty(); - if (whenCreated != null) { - table.setWhenCreatedColumn(whenCreated.getDbColumn()); - } - } - setIdentity(descriptor, table); - + MTable table = new MTable(descriptor); // add the table to the model ctx.addTable(table); @@ -66,43 +51,4 @@ public class ModelBuildBeanVisitor implements BeanVisitor { return new ModelBuildPropertyVisitor(ctx, table, descriptor); } - /** - * Set the identity type to use for this table. - *

- * Takes into account the requested identity type and the underlying support in the - * database platform. - *

- */ - private void setIdentity(BeanDescriptor descriptor, MTable table) { - - if (IdType.GENERATOR == descriptor.getIdType()) { - // explicit generator like UUID - table.setIdentityType(IdentityType.GENERATOR); - return; - } - if (IdType.EXTERNAL == descriptor.getIdType()) { - // externally defined code (lookup table, ISO country code etc) - table.setIdentityType(IdentityType.EXTERNAL); - return; - } - - int initialValue = descriptor.getSequenceInitialValue(); - int allocationSize = descriptor.getSequenceAllocationSize(); - - if (!descriptor.isIdTypePlatformDefault() || initialValue > 0 || allocationSize > 0) { - // explicitly set to use sequence or identity (generally not recommended practice) - if (IdType.IDENTITY == descriptor.getIdType()) { - if (!descriptor.isIdTypePlatformDefault()) { - table.setIdentityType(IdentityType.IDENTITY); - } - } else { - // explicit sequence defined - table.setIdentityType(IdentityType.SEQUENCE); - table.setSequenceName(descriptor.getSequenceName()); - table.setSequenceInitial(initialValue); - table.setSequenceAllocate(allocationSize); - } - } - } - } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java index b45962e06..10c9cc914 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java @@ -164,18 +164,9 @@ public class BeanDescriptor implements BeanType, STreeType { */ private final boolean idGeneratedValue; - private final boolean idTypePlatformDefault; - private final PlatformIdGenerator idGenerator; - /** - * The database sequence name (optional). - */ - private final String sequenceName; - - private final int sequenceInitialValue; - - private final int sequenceAllocationSize; + private final IdentityMode identityMode; /** * SQL used to return last inserted id. Used for Identity columns where @@ -456,13 +447,10 @@ public class BeanDescriptor implements BeanType, STreeType { this.changeLogFilter = deploy.getChangeLogFilter(); this.defaultSelectClause = deploy.getDefaultSelectClause(); - this.idType = deploy.getIdType(); + this.identityMode = deploy.getIdentityMode(); + this.idType = identityMode.getIdType(); this.idGeneratedValue = deploy.isIdGeneratedValue(); - this.idTypePlatformDefault = deploy.isIdTypePlatformDefault(); this.idGenerator = deploy.getIdGenerator(); - this.sequenceName = deploy.getSequenceName(); - this.sequenceInitialValue = deploy.getSequenceInitialValue(); - this.sequenceAllocationSize = deploy.getSequenceAllocationSize(); this.selectLastInsertedId = deploy.getSelectLastInsertedId(); this.selectLastInsertedIdDraft = deploy.getSelectLastInsertedIdDraft(); this.concurrencyMode = deploy.getConcurrencyMode(); @@ -3158,33 +3146,8 @@ public class BeanDescriptor implements BeanType, STreeType { return idGeneratedValue; } - /** - * Return true if the identity is the platform default (not explicitly set). - */ - public boolean isIdTypePlatformDefault() { - return idTypePlatformDefault; - } - - /** - * Return the sequence name. - */ - @Override - public String getSequenceName() { - return sequenceName; - } - - /** - * Return the sequence initial value. - */ - public int getSequenceInitialValue() { - return sequenceInitialValue; - } - - /** - * Return the sequence allocation size. - */ - public int getSequenceAllocationSize() { - return sequenceAllocationSize; + public IdentityMode getIdentityMode() { + return identityMode; } /** diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java index 72ce6ce7c..4899349ef 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java @@ -1354,42 +1354,39 @@ public class BeanDescriptorManager implements BeanDescriptorMap { return; } - if (IdType.SEQUENCE == desc.getIdType() && !dbIdentity.isSupportsSequence()) { + final IdentityMode identityMode = desc.getIdentityMode(); + if (identityMode.isSequence() && !dbIdentity.isSupportsSequence()) { // explicit sequence but not supported by the DatabasePlatform logger.info("Explicit sequence on " + desc.getFullName() + " but not supported by DB Platform - ignored"); - desc.setIdType(null); + identityMode.setIdType(IdType.AUTO); } - if (IdType.IDENTITY == desc.getIdType() && !dbIdentity.isSupportsIdentity()) { + if (identityMode.isIdentity() && !dbIdentity.isSupportsIdentity()) { // explicit identity but not supported by the DatabasePlatform logger.info("Explicit Identity on " + desc.getFullName() + " but not supported by DB Platform - ignored"); - desc.setIdType(null); + identityMode.setIdType(IdType.AUTO); } - if (desc.getIdType() == null) { + if (identityMode.isAuto()) { if (desc.isPrimaryKeyCompoundOrNonNumeric()) { - // assuming that this is a user supplied key like ISO country code or ISO currency code or lookup table code - logger.debug("Expecting user defined identity on {} - not using db sequence or autoincrement", desc.getFullName()); - desc.setIdType(IdType.EXTERNAL); + identityMode.setIdType(IdType.EXTERNAL); return; } if (desc.isIdGeneratedValue() || serverConfig.isIdGeneratorAutomatic()) { // use IDENTITY or SEQUENCE based on platform - desc.setIdType(dbIdentity.getIdType()); - desc.setIdTypePlatformDefault(); + identityMode.setPlatformType(dbIdentity.getIdType()); } else { // externally/application supplied Id values - desc.setIdType(IdType.EXTERNAL); + identityMode.setIdType(IdType.EXTERNAL); return; } } if (desc.getBaseTable() == null) { - // no base table so not going to set Identity - // of sequence information + // no base table so not going to set Identity or sequence information return; } - if (IdType.IDENTITY == desc.getIdType()) { + if (identityMode.isIdentity()) { // used when getGeneratedKeys is not supported (SQL Server 2000, SAP Hana) String selectLastInsertedId = dbIdentity.getSelectLastInsertedId(desc.getBaseTable()); String selectLastInsertedIdDraft = (!desc.isDraftable()) ? selectLastInsertedId : dbIdentity.getSelectLastInsertedId(desc.getDraftTable()); @@ -1397,21 +1394,21 @@ public class BeanDescriptorManager implements BeanDescriptorMap { return; } - if (IdType.SEQUENCE == desc.getIdType()) { - String seqName = desc.getIdGeneratorName(); - if (seqName != null) { - logger.debug("explicit sequence {} on {}", seqName, desc.getFullName()); - } else { + if (identityMode.isSequence()) { + String seqName = identityMode.getSequenceName(); + if (seqName == null || seqName.isEmpty()) { String primaryKeyColumn = desc.getSinglePrimaryKeyColumn(); - // use namingConvention to define sequence name seqName = namingConvention.getSequenceName(desc.getBaseTable(), primaryKeyColumn); } if (databasePlatform.isSequenceBatchMode()) { // use sequence next step 1 as we are going to batch fetch them instead - desc.setSequenceAllocationSize(1); + desc.setIdentitySequenceBatchMode(); + } + int stepSize = identityMode.getIncrement(); + if (stepSize == 0) { + stepSize = 50; } - int stepSize = desc.getSequenceAllocationSize(); desc.setIdGenerator(createSequenceIdGenerator(seqName, stepSize)); } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/IdentityMode.java b/src/main/java/io/ebeaninternal/server/deploy/IdentityMode.java new file mode 100644 index 000000000..03c6af391 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/deploy/IdentityMode.java @@ -0,0 +1,154 @@ +package io.ebeaninternal.server.deploy; + +import io.ebean.annotation.IdentityGenerated; +import io.ebean.annotation.IdentityType; +import io.ebean.config.dbplatform.IdType; + +public class IdentityMode { + + public static IdentityMode auto() { + return new IdentityMode(IdType.AUTO); + } + + public static IdentityMode none() { + return new IdentityMode(null); + } + + public static IdType idType(IdentityType type) { + switch (type) { + case AUTO: + return IdType.AUTO; + case SEQUENCE: + return IdType.SEQUENCE; + case IDENTITY: + return IdType.IDENTITY; + case APPLICATION: + return IdType.EXTERNAL; + default: + throw new IllegalStateException("type " + type + " not expected?"); + } + } + + private IdType type; + private IdentityGenerated generated; + private int start; + private int increment; + private int cache; + private String sequenceName; + private boolean platformDefault; + + public IdentityMode(IdType type, IdentityGenerated generated, int start, int increment, String seqName) { + this.type = type; + this.generated = generated; + this.start = start; + this.increment = increment; + this.sequenceName = seqName; + } + + /** + * Create from @SequenceGenerator annotation. + */ + public IdentityMode(int initialValue, int allocationSize, String sequenceName) { + this.type = IdType.AUTO; + this.generated = IdentityGenerated.AUTO; + this.sequenceName = sequenceName; + this.start = initialValue; + this.increment = allocationSize; + this.cache = 0; + } + + private IdentityMode(IdType type) { + this.type = type; + this.generated = IdentityGenerated.AUTO; + this.sequenceName = ""; + this.start = 0; + this.increment = 0; + this.cache = 0; + } + + public void setPlatformType(IdType type) { + this.type = type; + this.platformDefault = true; + } + + public void setSequence(int initialValue, int allocationSize, String sequenceName) { + this.start = initialValue; + this.increment = allocationSize; + this.sequenceName = sequenceName; + } + + public void setSequenceGenerator(String genName) { + if (sequenceName == null || sequenceName.isEmpty()) { + sequenceName = genName; + } + } + + public void setSequenceBatchMode() { + this.increment = 1; + } + + public void setIdType(IdType type) { + this.type = type; + } + + public void setStart(int start) { + this.start = start; + } + + public void setIncrement(int increment) { + this.increment = increment; + } + + public void setSequenceName(String sequenceName) { + this.sequenceName = sequenceName; + } + + public boolean isPlatformDefault() { + return platformDefault; + } + + public IdType getIdType() { + return type; + } + + public IdentityGenerated getGenerated() { + return generated; + } + + public int getStart() { + return start; + } + + public int getIncrement() { + return increment; + } + + public int getCache() { + return cache; + } + + public String getSequenceName() { + return sequenceName; + } + + public boolean isSequence() { + return type == IdType.SEQUENCE; + } + + public boolean isIdentity() { + return type == IdType.IDENTITY; + } + + public boolean isExternal() { + return type == IdType.EXTERNAL; + } + + public boolean isAuto() { + return type == IdType.AUTO; + } + + public boolean isDatabaseIdentity() { + return type != IdType.EXTERNAL && type != IdType.GENERATOR; + } + +} diff --git a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java index 0fdbe0954..522499bf3 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java +++ b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java @@ -25,6 +25,7 @@ import io.ebeaninternal.server.deploy.ChainedBeanPostConstructListener; import io.ebeaninternal.server.deploy.ChainedBeanPostLoad; import io.ebeaninternal.server.deploy.ChainedBeanQueryAdapter; import io.ebeaninternal.server.deploy.DeployPropertyParserMap; +import io.ebeaninternal.server.deploy.IdentityMode; import io.ebeaninternal.server.deploy.IndexDefinition; import io.ebeaninternal.server.deploy.InheritInfo; import io.ebeaninternal.server.deploy.PartitionMeta; @@ -85,24 +86,11 @@ public class DeployBeanDescriptor { private DeployBeanProperty orderColumn; - /** - * Type of Identity generation strategy used. - */ - private IdType idType; - private Class idClass; private DeployBeanPropertyAssocOne idClassProperty; - /** - * Set to true if the identity is default for the platform. - */ - private boolean idTypePlatformDefault; - - /** - * The name of an IdGenerator (optional). - */ - private String idGeneratorName; + private IdentityMode identityMode = IdentityMode.auto(); private PlatformIdGenerator idGenerator; @@ -111,15 +99,6 @@ public class DeployBeanDescriptor { */ private boolean idGeneratedValue; - /** - * The database sequence name (optional). - */ - private String sequenceName; - - private int sequenceInitialValue; - - private int sequenceAllocationSize = 50; - /** * Used with Identity columns but no getGeneratedKeys support. */ @@ -244,8 +223,7 @@ public class DeployBeanDescriptor { */ public void setPrimaryKeyJoin(TableJoin join) { this.primaryKeyJoin = join; - this.idType = IdType.EXTERNAL; - this.idGeneratorName = null; + this.identityMode.setIdType(IdType.EXTERNAL); this.idGenerator = null; } @@ -399,20 +377,40 @@ public class DeployBeanDescriptor { return entityType; } - public void setSequenceInitialValue(int sequenceInitialValue) { - this.sequenceInitialValue = sequenceInitialValue; + public IdentityMode getIdentityMode() { + return identityMode; } - public void setSequenceAllocationSize(int sequenceAllocationSize) { - this.sequenceAllocationSize = sequenceAllocationSize; + /** + * Set from @Identity + */ + public void setIdentityMode(IdentityMode identityMode) { + this.identityMode = identityMode; } - public int getSequenceInitialValue() { - return sequenceInitialValue; + /** + * Set from @Sequence + */ + public void setIdentitySequence(int initialValue, int allocationSize, String seqName) { + identityMode.setSequence(initialValue, allocationSize, seqName); } - public int getSequenceAllocationSize() { - return sequenceAllocationSize; + /** + * Potentially set sequence name from @GeneratedValue. + */ + public void setIdentitySequenceGenerator(String genName) { + identityMode.setSequenceGenerator(genName); + } + + /** + * Set use of Ebean side sequence batching. + */ + public void setIdentitySequenceBatchMode() { + identityMode.setSequenceBatchMode(); + } + + public void setIdentityType(IdType type) { + this.identityMode.setIdType(type); } public String[] getProperties() { @@ -760,48 +758,6 @@ public class DeployBeanDescriptor { this.name = name; } - /** - * Return the identity generation type. - */ - public IdType getIdType() { - return idType; - } - - /** - * Set the identity generation type. - */ - public void setIdType(IdType idType) { - this.idType = idType; - } - - /** - * Set when the identity type is the platform default. - */ - public void setIdTypePlatformDefault() { - this.idTypePlatformDefault = true; - } - - /** - * Return true when the identity is the platform default. - */ - public boolean isIdTypePlatformDefault() { - return idTypePlatformDefault; - } - - /** - * Return the DB sequence name (can be null). - */ - public String getSequenceName() { - return sequenceName; - } - - /** - * Set the DB sequence name. - */ - private void setSequenceName(String sequenceName) { - this.sequenceName = sequenceName; - } - /** * Return the SQL used to return the last inserted Id. *

@@ -824,21 +780,6 @@ public class DeployBeanDescriptor { this.selectLastInsertedIdDraft = selectLastInsertedIdDraft; } - /** - * Return the name of the IdGenerator that should be used with this type of - * bean. A null value could be used to specify the 'default' IdGenerator. - */ - public String getIdGeneratorName() { - return idGeneratorName; - } - - /** - * Set the name of the IdGenerator that should be used with this type of bean. - */ - public void setIdGeneratorName(String idGeneratorName) { - this.idGeneratorName = idGeneratorName; - } - /** * Return the actual IdGenerator for this bean type (can be null). */ @@ -851,9 +792,6 @@ public class DeployBeanDescriptor { */ public void setIdGenerator(PlatformIdGenerator idGenerator) { this.idGenerator = idGenerator; - if (idGenerator != null && idGenerator.isDbSequence()) { - setSequenceName(idGenerator.getName()); - } } /** @@ -871,25 +809,25 @@ public class DeployBeanDescriptor { } /** - * Assign the standard UUID generator. + * Assign the standard UUID generator if one has not been set. */ public void setUuidGenerator() { - this.idType = IdType.EXTERNAL; - this.idGeneratorName = PlatformIdGenerator.AUTO_UUID; + if (idGenerator == null) { + this.identityMode.setIdType(IdType.EXTERNAL); + switch (serverConfig.getUuidVersion()) { + case VERSION1: + this.idGenerator = UuidV1IdGenerator.getInstance(serverConfig.getUuidStateFile()); + break; - switch (serverConfig.getUuidVersion()) { - case VERSION1: - this.idGenerator = UuidV1IdGenerator.getInstance(serverConfig.getUuidStateFile()); - break; + case VERSION1RND: + this.idGenerator = UuidV1RndIdGenerator.INSTANCE; + break; - case VERSION1RND: - this.idGenerator = UuidV1RndIdGenerator.INSTANCE; - break; - - case VERSION4: - default: - this.idGenerator = UuidV4IdGenerator.INSTANCE; - break; + case VERSION4: + default: + this.idGenerator = UuidV4IdGenerator.INSTANCE; + break; + } } } @@ -897,8 +835,7 @@ public class DeployBeanDescriptor { * Assign a custom external IdGenerator. */ public void setCustomIdGenerator(PlatformIdGenerator idGenerator) { - this.idType = IdType.EXTERNAL; - this.idGeneratorName = idGenerator.getName(); + this.identityMode.setIdType(IdType.EXTERNAL); this.idGenerator = idGenerator; } @@ -951,7 +888,6 @@ public class DeployBeanDescriptor { * is non-numeric (and hence not suitable for db identity or sequence. */ public boolean isPrimaryKeyCompoundOrNonNumeric() { - DeployBeanProperty id = idProperty(); if (id == null) { return false; diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationFields.java b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationFields.java index 3def9df45..68638299b 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationFields.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationFields.java @@ -5,9 +5,9 @@ import io.ebean.annotation.CreatedTimestamp; import io.ebean.annotation.DbArray; import io.ebean.annotation.DbComment; import io.ebean.annotation.DbDefault; -import io.ebean.annotation.DbMap; import io.ebean.annotation.DbJson; import io.ebean.annotation.DbJsonB; +import io.ebean.annotation.DbMap; import io.ebean.annotation.DbMigration; import io.ebean.annotation.DocCode; import io.ebean.annotation.DocEmbedded; @@ -21,11 +21,11 @@ import io.ebean.annotation.Encrypted; import io.ebean.annotation.Expose; import io.ebean.annotation.Formula; import io.ebean.annotation.HistoryExclude; +import io.ebean.annotation.Identity; import io.ebean.annotation.Index; import io.ebean.annotation.JsonIgnore; import io.ebean.annotation.Length; import io.ebean.annotation.SoftDelete; -import io.ebean.annotation.Sum; import io.ebean.annotation.TenantId; import io.ebean.annotation.UnmappedJson; import io.ebean.annotation.UpdatedTimestamp; @@ -40,6 +40,7 @@ import io.ebean.config.dbplatform.DbEncryptFunction; import io.ebean.config.dbplatform.IdType; import io.ebean.config.dbplatform.PlatformIdGenerator; import io.ebeaninternal.server.deploy.DbMigrationInfo; +import io.ebeaninternal.server.deploy.IdentityMode; import io.ebeaninternal.server.deploy.IndexDefinition; import io.ebeaninternal.server.deploy.generatedproperty.GeneratedPropertyFactory; import io.ebeaninternal.server.deploy.meta.DeployBeanProperty; @@ -196,10 +197,8 @@ public class AnnotationFields extends AnnotationParser { readJsonAnnotations(prop); if (prop.getDbColumn() == null) { - // No @Column annotation or @Column.name() not set - // Use the NamingConvention to set the DB column name - String dbColumn = namingConvention.getColumnFromProperty(beanType, prop.getName()); - prop.setDbColumn(dbColumn); + // No @Column or @Column.name() so use NamingConvention + prop.setDbColumn(namingConvention.getColumnFromProperty(beanType, prop.getName())); } Id id = get(prop, Id.class); @@ -210,6 +209,10 @@ public class AnnotationFields extends AnnotationParser { if (id != null) { readIdScalar(prop); } + Identity identity = get(prop, Identity.class); + if (identity != null) { + readIdentity(identity); + } // determine the JDBC type using Lob/Temporal // otherwise based on the property Class @@ -381,6 +384,11 @@ public class AnnotationFields extends AnnotationParser { } } + private void readIdentity(Identity identity) { + final IdType idType = IdentityMode.idType(identity.type()); + descriptor.setIdentityMode(new IdentityMode(idType, identity.generated(), identity.start(), identity.increment(), identity.sequenceName())); + } + private void readDbMigration(DeployBeanProperty prop) { DbDefault dbDefault = get(prop, DbDefault.class); if (dbDefault != null) { @@ -521,34 +529,32 @@ public class AnnotationFields extends AnnotationParser { } } descriptor.setIdGeneratedValue(); - String genName = gen.generator(); - SequenceGenerator sequenceGenerator = find(prop, SequenceGenerator.class); - if (sequenceGenerator != null) { - if (sequenceGenerator.name().equals(genName)) { - genName = sequenceGenerator.sequenceName(); + SequenceGenerator seq = find(prop, SequenceGenerator.class); + if (seq != null) { + String seqName = seq.sequenceName(); + if (seqName.isEmpty()) { + seqName = namingConvention.getSequenceName(descriptor.getBaseTable(), prop.getDbColumn()); } - descriptor.setSequenceInitialValue(sequenceGenerator.initialValue()); - descriptor.setSequenceAllocationSize(sequenceGenerator.allocationSize()); + descriptor.setIdentitySequence(seq.initialValue(), seq.allocationSize(), seqName); } GenerationType strategy = gen.strategy(); - if (strategy == GenerationType.IDENTITY) { - descriptor.setIdType(IdType.IDENTITY); + descriptor.setIdentityType(IdType.IDENTITY); } else if (strategy == GenerationType.SEQUENCE) { - descriptor.setIdType(IdType.SEQUENCE); - if (!genName.isEmpty()) { - descriptor.setIdGeneratorName(genName); + descriptor.setIdentityType(IdType.SEQUENCE); + if (!gen.generator().isEmpty()) { + descriptor.setIdentitySequenceGenerator(gen.generator()); } } else if (strategy == GenerationType.AUTO) { - if (!genName.isEmpty()) { + if (!gen.generator().isEmpty()) { // use a custom IdGenerator - PlatformIdGenerator idGenerator = generatedPropFactory.getIdGenerator(genName); + PlatformIdGenerator idGenerator = generatedPropFactory.getIdGenerator(gen.generator()); if (idGenerator == null) { - throw new IllegalStateException("No custom IdGenerator registered with name " + genName); + throw new IllegalStateException("No custom IdGenerator registered with name " + gen.generator()); } descriptor.setCustomIdGenerator(idGenerator); } else if (prop.getPropertyType().equals(UUID.class)) { diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationParser.java b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationParser.java index 08cb701d7..d7ced0d5c 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationParser.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationParser.java @@ -67,10 +67,8 @@ public abstract class AnnotationParser extends AnnotationBase { prop.setImportedPrimaryKey(); } else { prop.setId(); - if (prop.getPropertyType().equals(UUID.class)) { - if (readConfig.isIdGeneratorAutomatic() && descriptor.getIdGeneratorName() == null) { - descriptor.setUuidGenerator(); - } + if (prop.getPropertyType().equals(UUID.class) && readConfig.isIdGeneratorAutomatic()) { + descriptor.setUuidGenerator(); } } }