Skip to content
This repository has been archived by the owner on Jun 13, 2024. It is now read-only.

Commit

Permalink
add support for different ID column names in entities
Browse files Browse the repository at this point in the history
  • Loading branch information
Miguel Diogo authored and grimsa committed Jul 21, 2017
1 parent d082947 commit 5445bce
Show file tree
Hide file tree
Showing 7 changed files with 220 additions and 190 deletions.
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,22 @@ Can be useful in environments where DDL statements cannot be executed from appli
}
```

1. Create a shared global temporary table, e.g.
2. Create a shared global temporary table, e.g.

```
create global temporary table HT_TEMP_IDS (ID CHAR(36), ENTITY_NAME VARCHAR(100));
```
2. Set the following Hibernate properties:
create global temporary table HT_TEMP_IDS (ID CHAR(36), ENTITY_NAME VARCHAR(100));
```
3. Set the following Hibernate properties:

```
configuration.setProperty(AvailableSettings.HQL_BULK_ID_STRATEGY, SingleGlobalTemporaryTableBulkIdStrategy.class.getName());
configuration.setProperty(SingleGlobalTemporaryTableBulkIdStrategy.TABLE, "HT_TEMP_IDS");
configuration.setProperty(SingleGlobalTemporaryTableBulkIdStrategy.DISCRIMINATOR_COLUMN, "ENTITY_NAME");
configuration.setProperty(SingleGlobalTemporaryTableBulkIdStrategy.ID_COLUMN, "ID"); // This is new in 1.2
configuration.setProperty(SingleGlobalTemporaryTableBulkIdStrategy.DISCRIMINATOR_COLUMN, "ENTITY_NAME"); // This is default in 1.2
configuration.setProperty(SingleGlobalTemporaryTableBulkIdStrategy.CLEAN_ROWS, "true");
```

## Release history
* 1.2 to be released
* 1.1 released 2016-09-29. Built for Hibernate 5.2
* 1.0 released 2016-09-29. Built for Hibernate 5.1 and JDK 1.8
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.github.grimsa.hibernate</groupId>
<artifactId>single-table-bulk-id-strategy</artifactId>
<version>1.1</version>
<version>1.2-SNAPSHOT</version>

<name>${project.groupId}:${project.artifactId}</name>
<description>Single Table Bulk ID Strategy for Hibernate</description>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,12 @@ public class SingleGlobalTemporaryTableBulkIdStrategy implements MultiTableBulkI
public static final String TABLE = "hibernate.hql.bulk_id_strategy.single_global_temporary.table";

/**
* Column to be used as entity discriminator
* Column to be used as entity id. Defaults to {@code ID}
*/
public static final String ID_COLUMN = "hibernate.hql.bulk_id_strategy.single_global_temporary.id_column";

/**
* Column to be used as entity discriminator. Defaults to {@code ENTITY_NAME}
*/
public static final String DISCRIMINATOR_COLUMN = "hibernate.hql.bulk_id_strategy.single_global_temporary.discriminator_column";

Expand All @@ -50,14 +55,16 @@ public class SingleGlobalTemporaryTableBulkIdStrategy implements MultiTableBulkI
public static final String CLEAN_ROWS = "hibernate.hql.bulk_id_strategy.single_global_temporary.clean_rows";

private String fullyQualifiedTableName;
private String idColumn;
private String discriminatorColumn;
private boolean cleanRows;

@Override
public void prepare(JdbcServices jdbcServices, JdbcConnectionAccess connectionAccess, MetadataImplementor metadata, SessionFactoryOptions sessionFactoryOptions) {
ConfigurationService configService = sessionFactoryOptions.getServiceRegistry().getService(ConfigurationService.class);
this.fullyQualifiedTableName = Objects.requireNonNull(configService.getSetting(TABLE, String.class, null), "Property " + TABLE + " must be set.");
this.discriminatorColumn = Objects.requireNonNull(configService.getSetting(DISCRIMINATOR_COLUMN, String.class, null), "Property " + DISCRIMINATOR_COLUMN + " must be set.");
this.idColumn = configService.getSetting(ID_COLUMN, String.class, "ID");
this.discriminatorColumn = configService.getSetting(DISCRIMINATOR_COLUMN, String.class, "ENTITY_NAME");
this.cleanRows = configService.getSetting(CLEAN_ROWS, StandardConverters.BOOLEAN, false);
}

Expand All @@ -69,18 +76,17 @@ public void release(JdbcServices jdbcServices, JdbcConnectionAccess connectionAc
public UpdateHandler buildUpdateHandler(SessionFactoryImplementor factory, HqlSqlWalker walker) {
final UpdateStatement updateStatement = (UpdateStatement) walker.getAST();
final Queryable targetedPersister = updateStatement.getFromClause().getFromElement().getQueryable();
final String discriminator = generateDiscriminatorValue(targetedPersister);

return new TableBasedUpdateHandlerImpl(factory, walker, this::getTableName) {

@Override
protected String generateIdSubselect(Queryable persister, IdTableInfo idTableInfo) {
return super.generateIdSubselect(persister, idTableInfo) + " where " + discriminatorColumn + "='" + discriminator + '\'';
return getTempTableIdSubselect(idTableInfo, targetedPersister);
}

@Override
protected void addAnyExtraIdSelectValues(SelectValues selectClause) {
selectClause.addColumn(null, '\'' + discriminator + '\'', discriminatorColumn);
addExtraIdSelectValues(targetedPersister, selectClause);
}

@Override
Expand All @@ -96,18 +102,17 @@ protected void releaseFromUse(Queryable persister, SharedSessionContractImplemen
public DeleteHandler buildDeleteHandler(SessionFactoryImplementor factory, HqlSqlWalker walker) {
final DeleteStatement deleteStatement = (DeleteStatement) walker.getAST();
final Queryable targetedPersister = deleteStatement.getFromClause().getFromElement().getQueryable();
final String discriminator = generateDiscriminatorValue(targetedPersister);

return new TableBasedDeleteHandlerImpl(factory, walker, this::getTableName) {

@Override
protected String generateIdSubselect(Queryable persister, IdTableInfo idTableInfo) {
return super.generateIdSubselect(persister, idTableInfo) + " where " + discriminatorColumn + "='" + discriminator + '\'';
return getTempTableIdSubselect(idTableInfo, targetedPersister);
}

@Override
protected void addAnyExtraIdSelectValues(SelectValues selectClause) {
selectClause.addColumn(null, '\'' + generateDiscriminatorValue(targetedPersister) + '\'', discriminatorColumn);
addExtraIdSelectValues(targetedPersister, selectClause);
}

@Override
Expand Down Expand Up @@ -140,6 +145,16 @@ protected String generateDiscriminatorValue(Queryable persister) {
return persister.getEntityName();
}

protected String getTempTableIdSubselect(IdTableInfo idTableInfo, Queryable persister) {
return "select " + idColumn
+ " from " + idTableInfo.getQualifiedIdTableName()
+ " where " + discriminatorColumn + "='" + generateDiscriminatorValue(persister) + "'";
}

protected void addExtraIdSelectValues(final Queryable targetedPersister, SelectValues selectClause) {
selectClause.addColumn(null, '\'' + generateDiscriminatorValue(targetedPersister) + '\'', discriminatorColumn);
}

private String getTableName() {
return fullyQualifiedTableName;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package lt.grimsa.hibernate.id;

import model.TestEntities.*;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.spi.LoggingEvent;
import org.hibernate.Transaction;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Configuration;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;

import static org.junit.Assert.assertTrue;

public abstract class AbstractSingleGlobalTemporaryTableBulkIdStrategyTest extends BaseCoreFunctionalTestCase {
private Logger sqlLogger = Logger.getLogger("org.hibernate.SQL");
private MessageCapturingAppender sqlAppender;
private boolean ddlExecuted;

@Override
protected void configure(Configuration configuration) {
configuration.setProperty(AvailableSettings.HQL_BULK_ID_STRATEGY, SingleGlobalTemporaryTableBulkIdStrategy.class.getName());
configuration.setProperty(SingleGlobalTemporaryTableBulkIdStrategy.TABLE, "HT_TEMP_IDS");
configuration.setProperty(SingleGlobalTemporaryTableBulkIdStrategy.DISCRIMINATOR_COLUMN, "ENTITY_NAME");
}

@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[]{Animal.class, Mammal.class, Reptile.class, Human.class, Dog.class};
}

@Override
protected void prepareTest() throws Exception {
sqlAppender = new MessageCapturingAppender();
openSession();
if (!ddlExecuted) {
doInTransaction(() -> session.createNativeQuery("create global temporary table HT_TEMP_IDS ("
+ getIdColumnName() + " CHAR(36), "
+ getEntityColumnName() + " VARCHAR(100))")
.executeUpdate());
ddlExecuted = true;
}
sqlLogger.addAppender(sqlAppender);
}

protected String getIdColumnName() {
return "ID";
}

protected String getEntityColumnName() {
return "ENTITY_NAME";
}

@Override
protected void cleanupTest() throws Exception {
sqlLogger.removeAppender(sqlAppender);
}

protected void doInTransaction(Runnable runnable) {
Transaction transaction = session.beginTransaction();
runnable.run();
transaction.commit();
}

protected void doWithLogging(Runnable runnable) {
sqlLogger.setLevel(Level.DEBUG);
runnable.run();
sqlLogger.setLevel(Level.OFF);
}

protected void verify(Predicate<List<String>> sqlLogConsumingPredicate) {
assertTrue(sqlLogConsumingPredicate.test(sqlAppender.log));
}

private static class MessageCapturingAppender extends AppenderSkeleton {
private final List<String> log = new ArrayList<>();

@Override
protected void append(LoggingEvent event) {
log.add(event.getRenderedMessage());
}

@Override
public boolean requiresLayout() {
return false;
}

@Override
public void close() {
}
}
}
Original file line number Diff line number Diff line change
@@ -1,62 +1,17 @@
package lt.grimsa.hibernate.id;

import static org.junit.Assert.assertTrue;

import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.spi.LoggingEvent;
import org.hibernate.Transaction;
import org.hibernate.cfg.AvailableSettings;
import model.TestEntities.Human;
import org.hibernate.cfg.Configuration;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.junit.Test;

import model.TestEntities.Animal;
import model.TestEntities.Dog;
import model.TestEntities.Human;
import model.TestEntities.Mammal;
import model.TestEntities.Reptile;

public class SingleGlobalTemporaryTableBulkIdStrategyRowCleanupTest extends BaseCoreFunctionalTestCase {

private Logger sqlLogger = Logger.getLogger("org.hibernate.SQL");

private MessageCapturingAppender sqlAppender;
private boolean ddlExecuted;
public class SingleGlobalTemporaryTableBulkIdStrategyRowCleanupTest extends AbstractSingleGlobalTemporaryTableBulkIdStrategyTest {

@Override
protected void configure(Configuration configuration) {
configuration.setProperty(AvailableSettings.HQL_BULK_ID_STRATEGY, SingleGlobalTemporaryTableBulkIdStrategy.class.getName());
configuration.setProperty(SingleGlobalTemporaryTableBulkIdStrategy.TABLE, "HT_TEMP_IDS");
configuration.setProperty(SingleGlobalTemporaryTableBulkIdStrategy.DISCRIMINATOR_COLUMN, "ENTITY_NAME");
super.configure(configuration);
configuration.setProperty(SingleGlobalTemporaryTableBulkIdStrategy.CLEAN_ROWS, "true");
}

@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] { Animal.class, Mammal.class, Reptile.class, Human.class, Dog.class };
}

@Override
protected void prepareTest() throws Exception {
sqlAppender = new MessageCapturingAppender();
openSession();
if (!ddlExecuted) {
doInTransaction(() -> session.createNativeQuery("create global temporary table HT_TEMP_IDS (ID CHAR(36), ENTITY_NAME VARCHAR(100))").executeUpdate());
ddlExecuted = true;
}
sqlLogger.addAppender(sqlAppender);
}

@Override
protected void cleanupTest() throws Exception {
sqlLogger.removeAppender(sqlAppender);
}

@Test
public void testDeleteCleansUpRows() {
// given
Expand All @@ -69,7 +24,7 @@ public void testDeleteCleansUpRows() {
});

// then: row delete statement was executed
assertTrue(sqlAppender.log.contains("delete from HT_TEMP_IDS where ENTITY_NAME=?"));
verify(sqlLog -> sqlLog.contains(("delete from HT_TEMP_IDS where ENTITY_NAME=?")));
}

@Test
Expand All @@ -84,36 +39,6 @@ public void testUpdateCleansUpRows() {
});

// then: row delete statement was executed
assertTrue(sqlAppender.log.contains("delete from HT_TEMP_IDS where ENTITY_NAME=?"));
}

private void doInTransaction(Runnable runnable) {
Transaction transaction = session.beginTransaction();
runnable.run();
transaction.commit();
}

private void doWithLogging(Runnable runnable) {
sqlLogger.setLevel(Level.DEBUG);
runnable.run();
sqlLogger.setLevel(Level.OFF);
}

private static class MessageCapturingAppender extends AppenderSkeleton {
private final List<String> log = new ArrayList<>();

@Override
protected void append(LoggingEvent event) {
log.add(event.getRenderedMessage());
}

@Override
public boolean requiresLayout() {
return false;
}

@Override
public void close() {
}
verify(sqlLog -> sqlLog.contains(("delete from HT_TEMP_IDS where ENTITY_NAME=?")));
}
}
Loading

0 comments on commit 5445bce

Please sign in to comment.