mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Support for @Identity - initial refactor to add IdentityMode
This commit is contained in:
@@ -87,7 +87,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-annotation</artifactId>
|
||||
<version>6.8</version>
|
||||
<version>6.9</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
@@ -35,6 +35,11 @@ public enum IdType {
|
||||
* Used when the key is a compound key or lookup table code.
|
||||
* </p>
|
||||
*/
|
||||
EXTERNAL
|
||||
EXTERNAL,
|
||||
|
||||
/**
|
||||
* Auto mapping to platform preferred identity strategy.
|
||||
*/
|
||||
AUTO
|
||||
|
||||
}
|
||||
|
||||
@@ -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<T> {
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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<String> 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.
|
||||
* <p>
|
||||
@@ -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<Column> 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
* <p>
|
||||
* Takes into account the requested identity type and the underlying support in the
|
||||
* database platform.
|
||||
* </p>
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -164,18 +164,9 @@ public class BeanDescriptor<T> implements BeanType<T>, 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<T> implements BeanType<T>, 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<T> implements BeanType<T>, 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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 <code>@SequenceGenerator</code> 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<T> {
|
||||
|
||||
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<T> {
|
||||
*/
|
||||
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<T> {
|
||||
*/
|
||||
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<T> {
|
||||
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 <code>@Identity</code>
|
||||
*/
|
||||
public void setIdentityMode(IdentityMode identityMode) {
|
||||
this.identityMode = identityMode;
|
||||
}
|
||||
|
||||
public int getSequenceInitialValue() {
|
||||
return sequenceInitialValue;
|
||||
/**
|
||||
* Set from <code>@Sequence</code>
|
||||
*/
|
||||
public void setIdentitySequence(int initialValue, int allocationSize, String seqName) {
|
||||
identityMode.setSequence(initialValue, allocationSize, seqName);
|
||||
}
|
||||
|
||||
public int getSequenceAllocationSize() {
|
||||
return sequenceAllocationSize;
|
||||
/**
|
||||
* Potentially set sequence name from <code>@GeneratedValue</code>.
|
||||
*/
|
||||
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<T> {
|
||||
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.
|
||||
* <p>
|
||||
@@ -824,21 +780,6 @@ public class DeployBeanDescriptor<T> {
|
||||
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<T> {
|
||||
*/
|
||||
public void setIdGenerator(PlatformIdGenerator idGenerator) {
|
||||
this.idGenerator = idGenerator;
|
||||
if (idGenerator != null && idGenerator.isDbSequence()) {
|
||||
setSequenceName(idGenerator.getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -871,25 +809,25 @@ public class DeployBeanDescriptor<T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<T> {
|
||||
* 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<T> {
|
||||
* is non-numeric (and hence not suitable for db identity or sequence.
|
||||
*/
|
||||
public boolean isPrimaryKeyCompoundOrNonNumeric() {
|
||||
|
||||
DeployBeanProperty id = idProperty();
|
||||
if (id == null) {
|
||||
return false;
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user