Repository: cayenne Updated Branches: refs/heads/master 17063b89f -> dd833a6c6
Added the ability to generate a primary key using sequences (since version MS SQL 2012) and 'NEWID()' in cayenne-server If the type of the key is integer, uses the sequences. If the key type is UNIQUEIDENTIFIER, uses the built-in function NEWID() Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/b18329b5 Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/b18329b5 Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/b18329b5 Branch: refs/heads/master Commit: b18329b5e32270b2fd275d898dd12ca92dbdd6d6 Parents: fd0d06e Author: Aleksey Pleshkanev <priest...@hotmail.com> Authored: Sun Mar 4 14:35:46 2018 +0300 Committer: Aleksey Pleshkanev <priest...@hotmail.com> Committed: Sun Mar 4 14:35:46 2018 +0300 ---------------------------------------------------------------------- .../cayenne/dba/sqlserver/SQLServerAdapter.java | 5 + .../dba/sqlserver/SQLServerPkGenerator.java | 129 +++++++++++++++++++ 2 files changed, 134 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cayenne/blob/b18329b5/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerAdapter.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerAdapter.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerAdapter.java index 6930094..d80cc3d 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerAdapter.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerAdapter.java @@ -30,6 +30,7 @@ import org.apache.cayenne.access.types.ExtendedTypeFactory; import org.apache.cayenne.access.types.ValueObjectTypeRegistry; import org.apache.cayenne.configuration.Constants; import org.apache.cayenne.configuration.RuntimeProperties; +import org.apache.cayenne.dba.PkGenerator; import org.apache.cayenne.dba.sybase.SybaseAdapter; import org.apache.cayenne.di.Inject; import org.apache.cayenne.map.EntityResolver; @@ -119,4 +120,8 @@ public class SQLServerAdapter extends SybaseAdapter { return translator; } + @Override + protected PkGenerator createPkGenerator() { + return new SQLServerPkGenerator(this); + } } http://git-wip-us.apache.org/repos/asf/cayenne/blob/b18329b5/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerPkGenerator.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerPkGenerator.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerPkGenerator.java new file mode 100644 index 0000000..820b8a4 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerPkGenerator.java @@ -0,0 +1,129 @@ +package org.apache.cayenne.dba.sqlserver; + +import org.apache.cayenne.CayenneRuntimeException; +import org.apache.cayenne.access.DataNode; +import org.apache.cayenne.dba.JdbcAdapter; +import org.apache.cayenne.dba.TypesMapping; +import org.apache.cayenne.dba.oracle.OraclePkGenerator; +import org.apache.cayenne.map.DbAttribute; +import org.apache.cayenne.map.DbEntity; +import org.apache.cayenne.map.DbKeyGenerator; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; + +/** + * The default PK generator for MS SQL, + * which uses sequences to generate a PK for an integer key type + * and NEWID() for UNIQUEIDENTIFIER key type + */ +public class SQLServerPkGenerator extends OraclePkGenerator { + + //MS SQL function for generating GUID + private static final String SELECT_NEW_GUID = "SELECT NEWID()"; + + private static final String SEQUENCE_PREFIX = "_pk"; + + private static final int MAX_LENGTH_GUID = 36; + + protected SQLServerPkGenerator(JdbcAdapter adapter) { + super(adapter); + } + + @Override + protected String createSequenceString(DbEntity ent) { + return "CREATE SEQUENCE " + sequenceName(ent) + + " AS [bigint] START WITH " + pkStartValue + " INCREMENT BY " + + pkCacheSize(ent) + " NO CACHE"; + } + + @Override + protected String getSequencePrefix() { + return SEQUENCE_PREFIX; + } + + @Override + protected String selectNextValQuery(String sequenceName) { + return "SELECT NEXT VALUE FOR " + sequenceName; + } + + @Override + public List<String> createAutoPkStatements(List<DbEntity> dbEntities) { + List<String> list = new ArrayList<>(dbEntities.size()); + for (DbEntity dbEntity : dbEntities) { + if (dbEntity.getPrimaryKeys().size() == 1) { + DbAttribute pk = dbEntity.getPrimaryKeys().iterator().next(); + if (TypesMapping.isNumeric(pk.getType())) { + list.add(createSequenceString(dbEntity)); + } + } + } + return list; + } + + @Override + public List<String> dropAutoPkStatements(List<DbEntity> dbEntities) { + List<String> list = new ArrayList<>(dbEntities.size()); + for (DbEntity dbEntity : dbEntities) { + if (dbEntity.getPrimaryKeys().size() == 1) { + DbAttribute pk = dbEntity.getPrimaryKeys().iterator().next(); + if (TypesMapping.isNumeric(pk.getType())) { + list.add(dropSequenceString(dbEntity)); + } + } + } + return list; + } + + @Override + public Object generatePk(DataNode node, DbAttribute pk) throws Exception { + DbEntity entity = pk.getEntity(); + + //check key on UNIQUEIDENTIFIER; UNIQUEIDENTIFIER is a character with a length of 35 + if (TypesMapping.isCharacter(pk.getType()) && pk.getMaxLength() == MAX_LENGTH_GUID) { + return guidPkFromDatabase(node, entity); + } else { + return super.generatePk(node, pk); + } + } + + @Override + protected String selectAllSequencesQuery() { + return "SELECT sch.name + '.' + seq.name" + + " FROM sys.sequences AS seq" + + " JOIN sys.schemas AS sch" + + " ON seq.schema_id = sch.schema_id"; + } + + @Override + protected String sequenceName(DbEntity entity) { + // use custom generator if possible + DbKeyGenerator keyGenerator = entity.getPrimaryKeyGenerator(); + if (keyGenerator != null && DbKeyGenerator.ORACLE_TYPE.equals(keyGenerator.getGeneratorType()) + && keyGenerator.getGeneratorName() != null) { + + return keyGenerator.getGeneratorName().toLowerCase(); + } else { + String seqName = entity.getName().toLowerCase() + getSequencePrefix(); + return adapter.getQuotingStrategy().quotedIdentifier(entity, entity.getSchema(), seqName); + } + } + + protected String guidPkFromDatabase(DataNode node, DbEntity entity) throws SQLException { + try (Connection con = node.getDataSource().getConnection()) { + try (Statement st = con.createStatement()) { + adapter.getJdbcEventLogger().log(SELECT_NEW_GUID); + try (ResultSet rs = st.executeQuery(SELECT_NEW_GUID)) { + if (!rs.next()) { + throw new CayenneRuntimeException("Error generating pk for DbEntity %s", entity.getName()); + } + return rs.getString(1); + } + } + } + } +}