Для тех, кто борется с этой проблемой, используя Grails 3 с gorm-hibernate5, я нашел решение, основанное на комментарии Грэма о grails-data-mapping # 880 .
Я реализовал пользовательскийSchemaManagementTool и добавил его в конфигурацию приложения:
hibernate.schema_management_tool = CustomSchemaManagementTool
Hibernate SchemaManagementTool в конечном итоге делегирует необработанные команды SQL в GenerationTarget (обычно GenerationTargetToDatabase ), поэтому наша цель - предоставить собственную GenerationTarget.
Это было бы проще всего, если бы мы могли переопределить HibernateSchemaManagementTool.buildGenerationTargets, но, к сожалению, это не раскрывается.Вместо этого нам нужно разработать наши собственные SchemaCreator и SchemaDropper и вернуть их в CustomSchemaManagementTool:
class CustomSchemaManagementTool extends HibernateSchemaManagementTool {
@Override
SchemaCreator getSchemaCreator(Map options) {
return new CustomSchemaCreator(this, getSchemaFilterProvider(options).getCreateFilter())
}
@Override
SchemaDropper getSchemaDropper(Map options) {
return new CustomSchemaDropper(this, getSchemaFilterProvider(options).getDropFilter())
}
// We unfortunately copy this private method from HibernateSchemaManagementTool
private SchemaFilterProvider getSchemaFilterProvider(Map options) {
final Object configuredOption = (options == null) ? null : options.get(AvailableSettings.HBM2DDL_FILTER_PROVIDER)
return serviceRegistry.getService(StrategySelector.class).resolveDefaultableStrategy(
SchemaFilterProvider.class,
configuredOption,
DefaultSchemaFilterProvider.INSTANCE
)
}
}
Для реализации SchemaCreator и SchemaDropper мы можем переопределить doCreation и doDrop соответственно.Они по существу скопированы из реализаций Hibernate, но с CustomGenerationTarget вместо GenerationTargetToDatabase:
class CustomSchemaCreator extends SchemaCreatorImpl {
private final HibernateSchemaManagementTool tool
CustomSchemaCreator(HibernateSchemaManagementTool tool, SchemaFilter schemaFilter) {
super(tool, schemaFilter)
this.tool = tool
}
@Override
void doCreation(Metadata metadata, ExecutionOptions options, SourceDescriptor sourceDescriptor, TargetDescriptor targetDescriptor) {
final JdbcContext jdbcContext = tool.resolveJdbcContext( options.getConfigurationValues() )
final GenerationTarget[] targets = new GenerationTarget[ targetDescriptor.getTargetTypes().size() ]
targets[0] = new CustomGenerationTarget(tool.getDdlTransactionIsolator(jdbcContext), true)
super.doCreation(metadata, jdbcContext.getDialect(), options, sourceDescriptor, targets)
}
}
class CustomSchemaDropper extends SchemaDropperImpl {
private final HibernateSchemaManagementTool tool
CustomSchemaDropper(HibernateSchemaManagementTool tool, SchemaFilter schemaFilter) {
super(tool, schemaFilter)
this.tool = tool
}
@Override
void doDrop(Metadata metadata, ExecutionOptions options, SourceDescriptor sourceDescriptor, TargetDescriptor targetDescriptor) {
final JdbcContext jdbcContext = tool.resolveJdbcContext( options.getConfigurationValues() )
final GenerationTarget[] targets = new GenerationTarget[ targetDescriptor.getTargetTypes().size() ]
targets[0] = new CustomGenerationTarget(tool.getDdlTransactionIsolator(jdbcContext), true)
super.doDrop(metadata, options, jdbcContext.getDialect(), sourceDescriptor, targets)
}
}
В этом случае я использую один и тот же CustomGenerationTarget для создания и удаления, но вы можете легко разделить это на разные классы,Теперь мы наконец-то получили отдачу, расширив GenerationTargetToDatabase и переопределив метод accept.Вызвав super.accept для сохраняемых операторов SQL, вы можете отфильтровать нежелательные операторы DDL.
class CustomGenerationTarget extends GenerationTargetToDatabase {
CustomGenerationTarget(DdlTransactionIsolator ddlTransactionIsolator, boolean releaseAfterUse) {
super(ddlTransactionIsolator, releaseAfterUse)
}
@Override
void accept(String command) {
if (shouldAccept(command))
super.accept(command)
}
boolean shouldAccept(String command) {
// Custom filtering logic here, e.g.:
if (command =~ /references legacy\.xyz/)
return false
return true
}
}
Это не самое элегантное решение, но вы можете выполнить свою работу.
Я также попытался предоставить свой собственный SchemaFilterProvider (и пользовательский SchemaFilter ).К сожалению, это позволяет только фильтровать таблицы / пространства имен, но не внешние ключи.