下面列出了org.hibernate.tool.schema.TargetType#org.hibernate.boot.Metadata 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/**
* Schema validation
*/
// TODO
private void validateSchema() {
try {
SessionFactory factory = this.localSessionFactory.unwrap(SessionFactory.class);
StandardServiceRegistry registry = factory.getSessionFactoryOptions().getServiceRegistry();
MetadataSources sources = new MetadataSources(registry);
sources.addPackage("org.unitedinternet.cosmo.model.hibernate");
Metadata metadata = sources.buildMetadata(registry);
new SchemaValidator().validate(metadata);
LOG.info("Schema validation passed");
} catch (HibernateException e) {
LOG.error("error validating schema", e);
throw e;
}
}
/**
* Register the provided classes by their simple name or relative package and class name.
*
* @param metadata metadata
* @param sessionFactory Hibernate session factory
* @param serviceRegistry Hibernate service registry
*/
@Override
public void integrate(
Metadata metadata,
SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
for(Class classImport : classImportList) {
String key;
if(excludedPath != null) {
key = classImport.getName().replace(excludedPath, "");
} else {
key = classImport.getSimpleName();
}
metadata.getImports().put(
key,
classImport.getName()
);
}
}
/**
* Initializes the table dependency tracker.
*
* @param metadata the Hibernate metadata
* @param schemaAction the kind of schema operation being done: {CREATE or DROP}.
*/
public void initializeDependencies(Metadata metadata, Action schemaAction) {
HashMap<Table, Table> dependencies = new HashMap<>();
for (Table childTable : metadata.collectTableMappings()) {
Interleaved interleaved = SchemaUtils.getInterleaveAnnotation(childTable, metadata);
if (interleaved != null) {
if (schemaAction == Action.CREATE || schemaAction == Action.UPDATE) {
// If creating tables, the parent blocks the child.
dependencies.put(childTable, SchemaUtils.getTable(interleaved.parentEntity(), metadata));
} else {
// If dropping tables, the child blocks the parent.
dependencies.put(SchemaUtils.getTable(interleaved.parentEntity(), metadata), childTable);
}
}
}
this.tableDependencies = dependencies;
this.processedTables = new HashSet<>();
}
private void addStatementAfterDdlBatch(Metadata metadata, String statement) {
// Find the RunBatchDdl auxiliary object which can run statements after the DDL batch.
Optional<RunBatchDdl> runBatchDdl =
metadata.getDatabase().getAuxiliaryDatabaseObjects().stream()
.filter(obj -> obj instanceof RunBatchDdl)
.map(obj -> (RunBatchDdl) obj)
.findFirst();
if (runBatchDdl.isPresent()) {
runBatchDdl.get().addAfterDdlStatement(statement);
} else {
throw new IllegalStateException(
"Failed to generate INSERT statement for the hibernate_sequence table. "
+ "The Spanner dialect did not create auxiliary database objects correctly. "
+ "Please post a question to "
+ "https://github.com/GoogleCloudPlatform/google-cloud-spanner-hibernate/issues");
}
}
private static List<Column> getSortedPkColumns(Table table, Metadata metadata) {
Interleaved interleaved = SchemaUtils.getInterleaveAnnotation(table, metadata);
if (interleaved == null) {
return table.getPrimaryKey().getColumns();
}
Table parentTable = SchemaUtils.getTable(interleaved.parentEntity(), metadata);
List<Column> sortedParentPkColumns = getSortedPkColumns(parentTable, metadata);
List<Column> sortedCurrentPkColumns = table.getPrimaryKey().getColumns().stream()
.filter(column -> !sortedParentPkColumns.contains(column))
.collect(Collectors.toList());
ArrayList<Column> currentPkColumns = new ArrayList<>();
currentPkColumns.addAll(sortedParentPkColumns);
currentPkColumns.addAll(sortedCurrentPkColumns);
return currentPkColumns;
}
private static SessionFactory makeSessionFactory(ServiceRegistry serviceRegistry) {
MetadataSources metadataSources = new MetadataSources(serviceRegistry);
metadataSources.addPackage("com.baeldung.hibernate.pojo");
metadataSources.addAnnotatedClass(com.baeldung.hibernate.joincolumn.OfficialEmployee.class);
metadataSources.addAnnotatedClass(Email.class);
metadataSources.addAnnotatedClass(Office.class);
metadataSources.addAnnotatedClass(OfficeAddress.class);
Metadata metadata = metadataSources.getMetadataBuilder()
.build();
return metadata.getSessionFactoryBuilder()
.build();
}
@Test
public void omitCreatingPreexistingTables() throws IOException, SQLException {
this.connection.setMetaData(MockJdbcUtils.metaDataBuilder()
.setTables("Employee")
.build());
Metadata employeeMetadata =
new MetadataSources(this.registry).addAnnotatedClass(Employee.class).buildMetadata();
String testFileName = UUID.randomUUID().toString();
new SchemaExport().setOutputFile(testFileName)
.createOnly(EnumSet.of(TargetType.STDOUT, TargetType.SCRIPT), employeeMetadata);
File scriptFile = new File(testFileName);
scriptFile.deleteOnExit();
List<String> statements = Files.readAllLines(scriptFile.toPath());
assertThat(statements).containsExactly(
// This omits creating the Employee table since it is declared to exist in metadata.
"START BATCH DDL",
"create table hibernate_sequence (next_val INT64) PRIMARY KEY ()",
"create index name_index on Employee (name)",
"alter table Employee add constraint FKiralam2duuhr33k8a10aoc2t6 "
+ "foreign key (manager_id) references Employee (id)",
"RUN BATCH",
"INSERT INTO hibernate_sequence (next_val) VALUES(1)"
);
}
@Test
public void generateCreateStringsNoPkEntityTest() {
assertThatThrownBy(() -> {
Metadata metadata = new MetadataSources(this.registry)
.addAnnotatedClass(NoPkEntity.class)
.buildMetadata();
new SchemaExport()
.setOutputFile("unused")
.createOnly(EnumSet.of(TargetType.STDOUT, TargetType.SCRIPT), metadata);
})
.isInstanceOf(AnnotationException.class)
.hasMessage(
"No identifier specified for entity: "
+ "com.google.cloud.spanner.hibernate.SpannerTableExporterTests$NoPkEntity");
}
@Override
public String getAlterTableToDropUniqueKeyCommand(UniqueKey uniqueKey, Metadata metadata) {
final JdbcEnvironment jdbcEnvironment = metadata.getDatabase().getJdbcEnvironment();
final String tableName = jdbcEnvironment.getQualifiedObjectNameFormatter().format(
uniqueKey.getTable().getQualifiedTableName(),
dialect
);
final StringBuilder buf = new StringBuilder( dialect.getAlterTableString(tableName) );
buf.append( getDropUnique() );
if ( dialect.supportsIfExistsBeforeConstraintName() ) {
buf.append( "if exists " );
}
buf.append( dialect.quote( uniqueKey.getName() ) );
if ( dialect.supportsIfExistsAfterConstraintName() ) {
buf.append( " if exists" );
}
return buf.toString();
}
/**
* Generates database create commands for the specified entities using Hibernate native API, SchemaExport.
* Creation commands are exported into the create.sql file.
*/
public static void generateSchema() {
Map<String, String> settings = new HashMap<>();
settings.put(Environment.URL, "jdbc:h2:mem:schema");
StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(settings).build();
MetadataSources metadataSources = new MetadataSources(serviceRegistry);
metadataSources.addAnnotatedClass(Account.class);
metadataSources.addAnnotatedClass(AccountSetting.class);
Metadata metadata = metadataSources.buildMetadata();
SchemaExport schemaExport = new SchemaExport();
schemaExport.setFormat(true);
schemaExport.setOutputFile("create.sql");
schemaExport.createOnly(EnumSet.of(TargetType.SCRIPT), metadata);
}
@Override
public void doCreation(
Metadata metadata,
ExecutionOptions options,
SourceDescriptor sourceDescriptor,
TargetDescriptor targetDescriptor) {
if ( targetDescriptor.getTargetTypes().isEmpty() ) {
return;
}
final JdbcContext jdbcContext = tool.resolveJdbcContext( options.getConfigurationValues() );
final GenerationTarget[] targets = tool.buildGenerationTargets(
targetDescriptor,
jdbcContext,
options.getConfigurationValues(),
true
);
doCreation( metadata, jdbcContext.getDialect(), options, sourceDescriptor, targets );
}
@SuppressWarnings("unchecked")
public void validate(Metadata metadata, ServiceRegistry serviceRegistry) {
LOG.runningSchemaValidator();
Map config = new HashMap();
config.putAll( serviceRegistry.getService( ConfigurationService.class ).getSettings() );
final SchemaManagementTool tool = serviceRegistry.getService( SchemaManagementTool.class );
final ExecutionOptions executionOptions = SchemaManagementToolCoordinator.buildExecutionOptions(
config,
ExceptionHandlerHaltImpl.INSTANCE
);
tool.getSchemaValidator( config ).doValidation( metadata, executionOptions );
}
@Override
protected void validateTables(
Metadata metadata,
DatabaseInformation databaseInformation,
ExecutionOptions options,
Dialect dialect,
Namespace namespace) {
for ( Table table : namespace.getTables() ) {
if ( schemaFilter.includeTable( table ) && table.isPhysicalTable() ) {
final TableInformation tableInformation = databaseInformation.getTableInformation(
table.getQualifiedTableName()
);
validateTable( table, tableInformation, metadata, options, dialect );
}
}
}
private static SessionFactory buildSessionFactory(Strategy strategy) {
try {
ServiceRegistry serviceRegistry = configureServiceRegistry();
MetadataSources metadataSources = new MetadataSources(serviceRegistry);
for (Class<?> entityClass : strategy.getEntityClasses()) {
metadataSources.addAnnotatedClass(entityClass);
}
Metadata metadata = metadataSources.getMetadataBuilder()
.build();
return metadata.getSessionFactoryBuilder()
.build();
} catch (IOException ex) {
throw new ExceptionInInitializerError(ex);
}
}
private static SessionFactoryBuilder getSessionFactoryBuilder(ServiceRegistry serviceRegistry) {
MetadataSources metadataSources = new MetadataSources(serviceRegistry);
metadataSources.addPackage("com.baeldung.hibernate.proxy");
metadataSources.addAnnotatedClass(Company.class);
metadataSources.addAnnotatedClass(Employee.class);
Metadata metadata = metadataSources.buildMetadata();
return metadata.getSessionFactoryBuilder();
}
/**
* For tests
*/
public void doDrop(Metadata metadata, boolean manageNamespaces, GenerationTarget... targets) {
final ServiceRegistry serviceRegistry = ( (MetadataImplementor) metadata ).getMetadataBuildingOptions().getServiceRegistry();
doDrop(
metadata,
serviceRegistry,
serviceRegistry.getService( ConfigurationService.class ).getSettings(),
manageNamespaces,
targets
);
}
private static SessionFactory buildSessionFactory() {
try {
ServiceRegistry serviceRegistry = configureServiceRegistry();
MetadataSources metadataSources = new MetadataSources(serviceRegistry);
metadataSources.addAnnotatedClass(Student.class);
Metadata metadata = metadataSources.getMetadataBuilder()
.applyBasicType(LocalDateStringType.INSTANCE)
.build();
return metadata.getSessionFactoryBuilder().build();
} catch (IOException ex) {
throw new ExceptionInInitializerError(ex);
}
}
@Override
public void integrate(
Metadata metadata,
SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
final EventListenerRegistry eventListenerRegistry =
serviceRegistry.getService( EventListenerRegistry.class );
eventListenerRegistry.appendListeners( EventType.PERSIST, RootAwareInsertEventListener.INSTANCE);
eventListenerRegistry.appendListeners( EventType.FLUSH_ENTITY, RootAwareUpdateAndDeleteEventListener.INSTANCE);
}
protected void applyIndexes(
Table table,
TableInformation tableInformation,
Dialect dialect,
Metadata metadata,
Formatter formatter,
ExecutionOptions options,
GenerationTarget... targets) {
final Exporter<Index> exporter = dialect.getIndexExporter();
final Iterator<Index> indexItr = table.getIndexIterator();
while ( indexItr.hasNext() ) {
final Index index = indexItr.next();
if ( !StringHelper.isEmpty( index.getName() ) ) {
IndexInformation existingIndex = null;
if ( tableInformation != null ) {
existingIndex = findMatchingIndex( index, tableInformation );
}
if ( existingIndex == null ) {
applySqlStrings(
false,
exporter.getSqlCreateStrings( index, metadata ),
formatter,
options,
targets
);
}
}
}
}
@Override
public void integrate(
Metadata metadata,
SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
this.database = metadata.getDatabase();
this.metadata = metadata;
}
@Override
public String getAlterTableToAddUniqueKeyCommand(UniqueKey uniqueKey, Metadata metadata) {
// Do this here, rather than allowing UniqueKey/Constraint to do it.
// We need full, simplified control over whether or not it happens.
final String tableName = metadata.getDatabase().getJdbcEnvironment().getQualifiedObjectNameFormatter().format(
uniqueKey.getTable().getQualifiedTableName(),
metadata.getDatabase().getJdbcEnvironment().getDialect()
);
final String constraintName = dialect.quote( uniqueKey.getName() );
return dialect.getAlterTableString( tableName )
+ " add constraint " + uniqueConstraintSql( uniqueKey ) + " constraint " + constraintName;
}
@Override
public DelayedDropAction buildDelayedAction(
Metadata metadata,
ExecutionOptions options,
SourceDescriptor sourceDescriptor) {
final JournalingGenerationTarget target = new JournalingGenerationTarget();
doDrop( metadata, options, tool.getServiceRegistry().getService( JdbcEnvironment.class ).getDialect(), sourceDescriptor, target );
return new DelayedDropActionImpl( target.commands );
}
@Override
public DelayedDropAction buildDelayedAction(
Metadata metadata, ExecutionOptions options, SourceDescriptor sourceDescriptor) {
try (Connection connection = tool.getDatabaseMetadataConnection(options)) {
// Initialize exporters with drop table dependencies so tables are dropped in the right order.
SpannerDatabaseInfo spannerDatabaseInfo = new SpannerDatabaseInfo(connection.getMetaData());
tool.getSpannerTableExporter(options).init(
metadata, spannerDatabaseInfo, Action.DROP);
tool.getForeignKeyExporter(options).init(spannerDatabaseInfo);
return schemaDropper.buildDelayedAction(metadata, options, sourceDescriptor);
} catch (SQLException e) {
throw new RuntimeException("Failed to update Spanner table schema.", e);
}
}
@Override
public String[] getSqlDropStrings(ForeignKey foreignKey, Metadata metadata) {
if (spannerDatabaseInfo == null) {
throw new IllegalStateException(
"Cannot determine which foreign keys to drop because spannerDatabaseInfo was null.");
}
if (foreignKeyExists(foreignKey)) {
return super.getSqlDropStrings(foreignKey, metadata);
} else {
return new String[0];
}
}
@Test
public void givenLegacyHbmImplNamingNamingStrategy_whenCreateDatabase_thenGetStrategyNames() {
Metadata metadata = MetadataExtractorIntegrator.INSTANCE.getMetadata();
String entity = Preference.class.getCanonicalName();
PersistentClass persistentClass = metadata.getEntityBinding(entity);
Collection<Table> tables = metadata
.getDatabase()
.getDefaultNamespace()
.getTables();
Table preferenceTable = persistentClass.getTable();
String tableNameExpected = "Account_preferences";
Table accountPreferencesTable = tables
.stream()
.filter(table -> table
.getName()
.equals(tableNameExpected))
.findFirst()
.get();
String implicitNameExpected = "account";
String implicitNameCreated = preferenceTable
.getColumn(3)
.getName();
String tableNameCreated = accountPreferencesTable.getName();
SoftAssertions.assertSoftly(softly -> {
softly
.assertThat(implicitNameCreated)
.isEqualTo(implicitNameExpected);
softly
.assertThat(tableNameCreated)
.isEqualTo(tableNameExpected);
});
}
/**
* Returns true if a table is generated by a Hibernate element collection.
*/
private boolean isElementCollection(Table table, Metadata metadata) {
for (Collection collection : metadata.getCollectionBindings()) {
if (collection.getCollectionTable().equals(table)) {
return true;
}
}
return false;
}
private List<String> getCreateTableStrings(
Table table, Metadata metadata, Iterable<Column> keyColumns) {
// Get the comma separated string of the primary keys of the table.
String primaryKeyColNames = StreamSupport.stream(keyColumns.spliterator(), false)
.map(Column::getQuotedName)
.collect(Collectors.joining(","));
// Get the comma separated string of all columns of the table.
Iterable<Column> columnIterable = () -> (Iterator<Column>) table.getColumnIterator();
String allColumnNames = StreamSupport.stream(columnIterable.spliterator(), false)
.map(column -> buildColumnTypeString(column, metadata))
.collect(Collectors.joining(","));
ArrayList<String> statements = new ArrayList<>();
// Build the Create Table string.
String createTableString = MessageFormat.format(
CREATE_TABLE_TEMPLATE,
table.getQuotedName(),
allColumnNames,
primaryKeyColNames,
getInterleavedClause(table, metadata));
statements.add(createTableString);
if (table.getName().equals(SequenceStyleGenerator.DEF_SEQUENCE_NAME)) {
// Caches the INSERT statement since DML statements must be run after a DDL batch.
addStatementAfterDdlBatch(
metadata,
"INSERT INTO " + SequenceStyleGenerator.DEF_SEQUENCE_NAME + " ("
+ SequenceStyleGenerator.DEF_VALUE_COLUMN + ") VALUES(1)");
}
return statements;
}
/**
* Starts Hibernate.
*
* @param accessType Cache access type.
* @param igniteInstanceName Ignite instance name.
* @return Session factory.
*/
private SessionFactory startHibernate(org.hibernate.cache.spi.access.AccessType accessType, String igniteInstanceName) {
StandardServiceRegistryBuilder builder = registryBuilder();
for (Map.Entry<String, String> e : hibernateProperties(igniteInstanceName, accessType.name()).entrySet())
builder.applySetting(e.getKey(), e.getValue());
// Use the same cache for Entity and Entity2.
builder.applySetting(REGION_CACHE_PROPERTY + ENTITY2_NAME, ENTITY_NAME);
StandardServiceRegistry srvcRegistry = builder.build();
MetadataSources metadataSources = new MetadataSources(srvcRegistry);
for (Class entityClass : getAnnotatedClasses())
metadataSources.addAnnotatedClass(entityClass);
Metadata metadata = metadataSources.buildMetadata();
for (PersistentClass entityBinding : metadata.getEntityBindings()) {
if (!entityBinding.isInherited())
((RootClass)entityBinding).setCacheConcurrencyStrategy(accessType.getExternalName());
}
for (org.hibernate.mapping.Collection collectionBinding : metadata.getCollectionBindings())
collectionBinding.setCacheConcurrencyStrategy(accessType.getExternalName() );
return metadata.buildSessionFactory();
}
@Test
public void testCreateInterleavedTables() {
Metadata metadata =
new MetadataSources(this.registry)
.addAnnotatedClass(Child.class)
.addAnnotatedClass(GrandParent.class)
.addAnnotatedClass(Parent.class)
.buildMetadata();
Session session = metadata.buildSessionFactory().openSession();
session.beginTransaction();
session.close();
List<String> sqlStrings =
connection.getStatementResultSetHandler().getExecutedStatements();
assertThat(sqlStrings).containsExactly(
"START BATCH DDL",
"RUN BATCH",
"START BATCH DDL",
"create table GrandParent (grandParentId INT64 not null,name STRING(255)) "
+ "PRIMARY KEY (grandParentId)",
"create table Parent (grandParentId INT64 not null,"
+ "parentId INT64 not null,name STRING(255)) PRIMARY KEY (grandParentId,parentId), "
+ "INTERLEAVE IN PARENT GrandParent",
"create table Child (childId INT64 not null,grandParentId INT64 not null,"
+ "parentId INT64 not null,name STRING(255)) "
+ "PRIMARY KEY (grandParentId,parentId,childId), "
+ "INTERLEAVE IN PARENT Parent",
"create table hibernate_sequence (next_val INT64) PRIMARY KEY ()",
"RUN BATCH",
"INSERT INTO hibernate_sequence (next_val) VALUES(1)"
);
}
protected void validateColumnType(
Table table,
Column column,
ColumnInformation columnInformation,
Metadata metadata,
ExecutionOptions options,
Dialect dialect) {
boolean typesMatch = column.getSqlTypeCode( metadata ) == columnInformation.getTypeCode()
|| column.getSqlType( dialect, metadata ).toLowerCase(Locale.ROOT).startsWith( columnInformation.getTypeName().toLowerCase(Locale.ROOT) );
if ( !typesMatch ) {
throw new SchemaManagementException(
String.format(
"Schema-validation: wrong column type encountered in column [%s] in " +
"table [%s]; found [%s (Types#%s)], but expecting [%s (Types#%s)]",
column.getName(),
table.getQualifiedTableName(),
columnInformation.getTypeName().toLowerCase(Locale.ROOT),
JdbcTypeNameMapper.getTypeName( columnInformation.getTypeCode() ),
column.getSqlType().toLowerCase(Locale.ROOT),
JdbcTypeNameMapper.getTypeName( column.getSqlTypeCode( metadata ) )
)
);
}
// this is the old Hibernate check...
//
// but I think a better check involves checks against type code and then the type code family, not
// just the type name.
//
// See org.hibernate.type.descriptor.sql.JdbcTypeFamilyInformation
// todo : this ^^
}