HHH-15770 add in all the commonly-supported OnDeleteActions

This commit is contained in:
Gavin 2022-11-27 01:58:09 +01:00 committed by Gavin King
parent c9caf292e6
commit 76f92bd901
13 changed files with 121 additions and 72 deletions

View File

@ -6,7 +6,7 @@
*/
package org.hibernate.annotations;
import org.hibernate.AssertionFailure;
import static java.util.Locale.ROOT;
/**
* Enumerates the possible actions for the {@code on delete} clause
@ -21,24 +21,38 @@ import org.hibernate.AssertionFailure;
public enum OnDeleteAction {
/**
* No action. The default.
* No action. The default. An error is raised if rows still reference
* the parent when the constraint is checked, possibly later in the
* transaction.
*/
NO_ACTION,
/**
* Cascade deletion of the parent to the child.
*/
CASCADE;
CASCADE,
/**
* Prevents deletion of the parent by raising an error immediately.
*/
RESTRICT,
/**
* Set the referencing foreign key to null.
*/
SET_NULL,
/**
* Set the referencing foreign key to its default value.
*/
SET_DEFAULT;
public String getAlternativeName() {
switch (this) {
case NO_ACTION:
return "no-action";
case CASCADE:
return "cascade";
default:
throw new AssertionFailure("unknown action");
}
return toString().toLowerCase(ROOT).replace('_', '-');
}
public String toSqlString() {
return toString().toLowerCase(ROOT).replace('_', ' ');
}
public static OnDeleteAction fromExternalForm(Object value) {

View File

@ -1649,7 +1649,7 @@ public final class AnnotationBinder {
BinderHelper.getCascadeStrategy( null, hibernateCascade, false, forcePersist ),
//@Any has no cascade attribute
joinColumns,
onDeleteAnn != null && OnDeleteAction.CASCADE == onDeleteAnn.action(),
onDeleteAnn == null ? null : onDeleteAnn.action(),
nullability,
propertyHolder,
inferredData,
@ -2331,7 +2331,7 @@ public final class AnnotationBinder {
private static void bindAny(
String cascadeStrategy,
AnnotatedJoinColumns columns,
boolean cascadeOnDelete,
OnDeleteAction onDeleteAction,
Nullability nullability,
PropertyHolder propertyHolder,
PropertyData inferredData,
@ -2350,7 +2350,7 @@ public final class AnnotationBinder {
getOverridableAnnotation( property, Formula.class, context ),
columns,
inferredData,
cascadeOnDelete,
onDeleteAction,
lazy,
nullability,
propertyHolder,

View File

@ -36,6 +36,7 @@ import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
import org.hibernate.annotations.DialectOverride;
import org.hibernate.annotations.Formula;
import org.hibernate.annotations.OnDeleteAction;
import org.hibernate.annotations.SqlFragmentAlias;
import org.hibernate.annotations.common.reflection.XAnnotatedElement;
import org.hibernate.annotations.common.reflection.XClass;
@ -1035,7 +1036,7 @@ public class BinderHelper {
Formula discriminatorFormula,
AnnotatedJoinColumns keyColumns,
PropertyData inferredData,
boolean cascadeOnDelete,
OnDeleteAction onDeleteAction,
boolean lazy,
Nullability nullability,
PropertyHolder propertyHolder,
@ -1046,7 +1047,7 @@ public class BinderHelper {
final Any value = new Any( context, keyColumns.getTable(), true );
value.setLazy( lazy );
value.setCascadeDeleteEnabled( cascadeOnDelete );
value.setOnDeleteAction( onDeleteAction );
final BasicValueBinder discriminatorValueBinder =
new BasicValueBinder( BasicValueBinder.Kind.ANY_DISCRIMINATOR, context );

View File

@ -14,6 +14,7 @@ import org.hibernate.AnnotationException;
import org.hibernate.MappingException;
import org.hibernate.annotations.LazyGroup;
import org.hibernate.annotations.NotFoundAction;
import org.hibernate.annotations.OnDeleteAction;
import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.boot.spi.MetadataBuildingContext;
@ -50,7 +51,7 @@ public class OneToOneSecondPass implements SecondPass {
private final NotFoundAction notFoundAction;
private final PropertyData inferredData;
private final XClass targetEntity;
private final boolean cascadeOnDelete;
private final OnDeleteAction onDeleteAction;
private final boolean optional;
private final String cascadeStrategy;
private final AnnotatedJoinColumns joinColumns;
@ -64,7 +65,7 @@ public class OneToOneSecondPass implements SecondPass {
PropertyData inferredData,
XClass targetEntity,
NotFoundAction notFoundAction,
boolean cascadeOnDelete,
OnDeleteAction onDeleteAction,
boolean optional,
String cascadeStrategy,
AnnotatedJoinColumns columns,
@ -77,7 +78,7 @@ public class OneToOneSecondPass implements SecondPass {
this.notFoundAction = notFoundAction;
this.inferredData = inferredData;
this.targetEntity = targetEntity;
this.cascadeOnDelete = cascadeOnDelete;
this.onDeleteAction = onDeleteAction;
this.optional = optional;
this.cascadeStrategy = cascadeStrategy;
this.joinColumns = columns;
@ -97,7 +98,7 @@ public class OneToOneSecondPass implements SecondPass {
XProperty property = inferredData.getProperty();
ToOneBinder.defineFetchingStrategy( value, property, inferredData, propertyHolder );
//value.setFetchMode( fetchMode );
value.setCascadeDeleteEnabled( cascadeOnDelete );
value.setOnDeleteAction(onDeleteAction);
//value.setLazy( fetchMode != FetchMode.JOIN );
value.setConstrained( !optional );
@ -174,7 +175,7 @@ public class OneToOneSecondPass implements SecondPass {
final ManyToOne manyToOne = new ManyToOne( buildingContext, mappedByJoin.getTable() );
//FIXME use ignore not found here
manyToOne.setNotFoundAction( notFoundAction );
manyToOne.setCascadeDeleteEnabled( oneToOne.isCascadeDeleteEnabled() );
manyToOne.setOnDeleteAction( oneToOne.getOnDeleteAction() );
manyToOne.setFetchMode( oneToOne.getFetchMode() );
manyToOne.setLazy( oneToOne.isLazy() );
manyToOne.setReferencedEntityName( oneToOne.getReferencedEntityName() );
@ -285,7 +286,7 @@ public class OneToOneSecondPass implements SecondPass {
join.setKey( key );
//TODO support for inverse and optional
join.setOptional( true ); //perhaps not quite per-spec, but a Good Thing anyway
key.setCascadeDeleteEnabled( false );
key.setOnDeleteAction( null );
for ( Column column: otherSideProperty.getValue().getColumns() ) {
Column copy = new Column();
copy.setLength( column.getLength() );

View File

@ -100,7 +100,7 @@ public class ToOneBinder {
joinColumns,
!mandatory,
notFoundAction,
onDelete != null && OnDeleteAction.CASCADE == onDelete.action(),
onDelete == null ? null : onDelete.action(),
getTargetEntity( inferredData, context ),
propertyHolder,
inferredData,
@ -130,7 +130,7 @@ public class ToOneBinder {
AnnotatedJoinColumns joinColumns,
boolean optional,
NotFoundAction notFoundAction,
boolean cascadeOnDelete,
OnDeleteAction onDeleteAction,
XClass targetEntity,
PropertyHolder propertyHolder,
PropertyData inferredData,
@ -151,7 +151,7 @@ public class ToOneBinder {
defineFetchingStrategy( value, property, inferredData, propertyHolder );
//value.setFetchMode( fetchMode );
value.setNotFoundAction( notFoundAction );
value.setCascadeDeleteEnabled( cascadeOnDelete );
value.setOnDeleteAction( onDeleteAction );
//value.setLazy( fetchMode != FetchMode.JOIN );
if ( !optional ) {
for ( AnnotatedJoinColumn column : joinColumns.getJoinColumns() ) {
@ -425,7 +425,7 @@ public class ToOneBinder {
!mandatory,
getFetchMode( oneToOne.fetch() ),
notFoundAction,
onDelete != null && OnDeleteAction.CASCADE == onDelete.action(),
onDelete == null ? null : onDelete.action(),
getTargetEntity( inferredData, context ),
propertyHolder,
inferredData,
@ -444,7 +444,7 @@ public class ToOneBinder {
boolean optional,
FetchMode fetchMode,
NotFoundAction notFoundAction,
boolean cascadeOnDelete,
OnDeleteAction cascadeOnDelete,
XClass targetEntity,
PropertyHolder propertyHolder,
PropertyData inferredData,

View File

@ -212,7 +212,7 @@ public abstract class CollectionBinder {
private String cacheRegionName;
private boolean oneToMany;
protected IndexColumn indexColumn;
protected boolean cascadeDeleteEnabled;
protected OnDeleteAction onDeleteAction;
protected String mapKeyPropertyName;
private boolean insertable = true;
private boolean updatable = true;
@ -288,7 +288,7 @@ public abstract class CollectionBinder {
collectionBinder.setAccessType( inferredData.getDefaultAccess() );
collectionBinder.setEmbedded( property.isAnnotationPresent( Embedded.class ) );
collectionBinder.setProperty( property );
collectionBinder.setCascadeDeleteEnabled( hasOnDeleteCascade( property ) );
collectionBinder.setOnDeleteActionAction( onDeleteAction( property ) );
collectionBinder.setInheritanceStatePerClass( inheritanceStatePerClass );
collectionBinder.setDeclaringClass( inferredData.getDeclaringClass() );
@ -394,9 +394,9 @@ public abstract class CollectionBinder {
);
}
private static boolean hasOnDeleteCascade(XProperty property) {
private static OnDeleteAction onDeleteAction(XProperty property) {
final OnDelete onDelete = property.getAnnotation( OnDelete.class );
return onDelete != null && OnDeleteAction.CASCADE == onDelete.action();
return onDelete == null ? null : onDelete.action();
}
private static PropertyData virtualPropertyData(PropertyData inferredData, XProperty property) {
@ -1631,7 +1631,7 @@ public abstract class CollectionBinder {
handleWhere( false );
final PersistentClass targetEntity = persistentClasses.get( getElementType().getName() );
bindCollectionSecondPass( targetEntity, foreignJoinColumns, cascadeDeleteEnabled );
bindCollectionSecondPass( targetEntity, foreignJoinColumns, onDeleteAction);
if ( !collection.isInverse() && !collection.getKey().isNullable() ) {
createOneToManyBackref( oneToMany );
@ -1906,7 +1906,7 @@ public abstract class CollectionBinder {
private DependantValue buildCollectionKey(
Collection collection,
AnnotatedJoinColumns joinColumns,
boolean cascadeDeleteEnabled,
OnDeleteAction onDeleteAction,
boolean noConstraintByDefault,
XProperty property,
PropertyHolder propertyHolder) {
@ -1928,7 +1928,7 @@ public abstract class CollectionBinder {
final List<AnnotatedColumn> columns = joinColumns.getColumns();
key.setNullable( columns.isEmpty() || columns.get(0).isNullable() );
key.setUpdateable( columns.isEmpty() || columns.get(0).isUpdatable() );
key.setCascadeDeleteEnabled( cascadeDeleteEnabled );
key.setOnDeleteAction( onDeleteAction );
collection.setKey( key );
if ( property != null ) {
@ -2088,7 +2088,7 @@ public abstract class CollectionBinder {
bindFilters( isCollectionOfEntities );
handleWhere( isCollectionOfEntities );
bindCollectionSecondPass( targetEntity, joinColumns, cascadeDeleteEnabled );
bindCollectionSecondPass( targetEntity, joinColumns, onDeleteAction);
if ( isCollectionOfEntities ) {
final ManyToOne element = handleCollectionOfEntities(
@ -2106,7 +2106,7 @@ public abstract class CollectionBinder {
handleManyToAny(
collection,
inverseJoinColumns,
cascadeDeleteEnabled,
onDeleteAction,
property,
buildingContext
);
@ -2356,7 +2356,7 @@ public abstract class CollectionBinder {
private void handleManyToAny(
Collection collection,
AnnotatedJoinColumns inverseJoinColumns,
boolean cascadeDeleteEnabled,
OnDeleteAction onDeleteAction,
XProperty property,
MetadataBuildingContext buildingContext) {
//@ManyToAny
@ -2381,7 +2381,7 @@ public abstract class CollectionBinder {
discriminatorFormulaAnn,
inverseJoinColumns,
inferredData,
cascadeDeleteEnabled,
onDeleteAction,
anyAnn.fetch() == LAZY,
Nullability.NO_CONSTRAINT,
propertyHolder,
@ -2579,7 +2579,7 @@ public abstract class CollectionBinder {
private void bindCollectionSecondPass(
PersistentClass targetEntity,
AnnotatedJoinColumns joinColumns,
boolean cascadeDeleteEnabled) {
OnDeleteAction onDeleteAction) {
if ( !hasMappedBy() ) {
createSyntheticPropertyReference(
@ -2596,7 +2596,7 @@ public abstract class CollectionBinder {
final DependantValue key = buildCollectionKey(
collection,
joinColumns,
cascadeDeleteEnabled,
onDeleteAction,
buildingContext.getBuildingOptions().isNoConstraintByDefault(),
property,
propertyHolder
@ -2617,8 +2617,8 @@ public abstract class CollectionBinder {
key.sortProperties();
}
public void setCascadeDeleteEnabled(boolean onDeleteCascade) {
this.cascadeDeleteEnabled = onDeleteCascade;
public void setOnDeleteActionAction(OnDeleteAction onDeleteAction) {
this.onDeleteAction = onDeleteAction;
}
String safeCollectionRole() {

View File

@ -58,7 +58,6 @@ import org.hibernate.annotations.Immutable;
import org.hibernate.annotations.Loader;
import org.hibernate.annotations.NaturalIdCache;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;
import org.hibernate.annotations.OptimisticLockType;
import org.hibernate.annotations.OptimisticLocking;
import org.hibernate.annotations.Persister;
@ -672,7 +671,7 @@ public class EntityBinder {
jsc.setKey( key );
handleForeignKeys( annotatedClass, context, key );
final OnDelete onDelete = annotatedClass.getAnnotation( OnDelete.class );
key.setCascadeDeleteEnabled( onDelete != null && OnDeleteAction.CASCADE == onDelete.action() );
key.setOnDeleteAction( onDelete == null ? null : onDelete.action() );
//we are never in a second pass at that stage, so queue it
context.getMetadataCollector()
.addSecondPass( new JoinedSubclassFkSecondPass( jsc, joinColumns, key, context) );
@ -1732,7 +1731,7 @@ public class EntityBinder {
DependantValue key = new DependantValue( context, join.getTable(), persistentClass.getIdentifier() );
join.setKey( key );
setForeignKeyNameIfDefined( join );
key.setCascadeDeleteEnabled( false );
key.setOnDeleteAction( null );
TableBinder.bindForeignKey( persistentClass, null, joinColumns, key, false, context );
key.sortProperties();
join.createPrimaryKey();

View File

@ -2923,7 +2923,7 @@ public abstract class Dialect implements ConversionContext {
/**
* Does this dialect support column-level check constraints?
*
* @return True if column-level {@code CHECK} constraints are supported;
* @return True if column-level {@code check} constraints are supported;
* false otherwise.
*/
public boolean supportsColumnCheck() {
@ -2933,7 +2933,7 @@ public abstract class Dialect implements ConversionContext {
/**
* Does this dialect support table-level check constraints?
*
* @return True if table-level {@code CHECK} constraints are supported;
* @return True if table-level {@code check} constraints are supported;
* false otherwise.
*/
public boolean supportsTableCheck() {
@ -2941,9 +2941,9 @@ public abstract class Dialect implements ConversionContext {
}
/**
* Does this dialect support cascaded delete on foreign key definitions?
* Does this dialect support {@code on delete} actions in foreign key definitions?
*
* @return {@code true} indicates that the dialect does support cascaded delete on foreign keys.
* @return {@code true} if the dialect does support the {@code on delete} clause.
*/
public boolean supportsCascadeDelete() {
return true;

View File

@ -168,7 +168,7 @@ public class DefaultDeleteEventListener implements DeleteEventListener, Callback
EntityPersister persister = source.getEntityPersister( event.getEntityName(), entity );
if ( ForeignKeys.isTransient( persister.getEntityName(), entity, null, source ) ) {
deleteTransientEntity( source, entity, event.isCascadeDeleteEnabled(), persister, transientEntities );
deleteTransientEntity( source, entity, persister, transientEntities );
}
else {
performDetachedEntityDeletionCheck( event );
@ -320,7 +320,6 @@ public class DefaultDeleteEventListener implements DeleteEventListener, Callback
*
* @param session The session which is the source of the event
* @param entity The entity being delete processed
* @param cascadeDeleteEnabled Is cascading of deletes enabled
* @param persister The entity persister
* @param transientEntities A cache of already visited transient entities
* (to avoid infinite recursion).
@ -328,7 +327,6 @@ public class DefaultDeleteEventListener implements DeleteEventListener, Callback
protected void deleteTransientEntity(
EventSource session,
Object entity,
boolean cascadeDeleteEnabled,
EntityPersister persister,
DeleteContext transientEntities) {
LOG.handlingTransientEntity();
@ -336,7 +334,7 @@ public class DefaultDeleteEventListener implements DeleteEventListener, Callback
LOG.trace( "Already handled transient entity; skipping" );
return;
}
cascadeBeforeDelete( session, persister, entity, null, transientEntities );
cascadeBeforeDelete( session, persister, entity, transientEntities );
cascadeAfterDelete( session, persister, entity, transientEntities );
}
@ -390,7 +388,7 @@ public class DefaultDeleteEventListener implements DeleteEventListener, Callback
persistenceContext.setEntryStatus( entityEntry, Status.DELETED );
final EntityKey key = session.generateEntityKey( entityEntry.getId(), persister );
cascadeBeforeDelete( session, persister, entity, entityEntry, transientEntities );
cascadeBeforeDelete( session, persister, entity, transientEntities );
new ForeignKeys.Nullifier( entity, true, false, session, persister )
.nullifyTransientReferences( entityEntry.getDeletedState() );
@ -493,7 +491,6 @@ public class DefaultDeleteEventListener implements DeleteEventListener, Callback
EventSource session,
EntityPersister persister,
Object entity,
EntityEntry entityEntry,
DeleteContext transientEntities) throws HibernateException {
CacheMode cacheMode = session.getCacheMode();

View File

@ -11,6 +11,7 @@ import java.util.Iterator;
import java.util.List;
import org.hibernate.MappingException;
import org.hibernate.annotations.OnDeleteAction;
import org.hibernate.boot.model.relational.SqlStringGenerationContext;
import org.hibernate.dialect.Dialect;
import org.hibernate.internal.util.StringHelper;
@ -24,7 +25,7 @@ public class ForeignKey extends Constraint {
private Table referencedTable;
private String referencedEntityName;
private String keyDefinition;
private boolean cascadeDeleteEnabled;
private OnDeleteAction onDeleteAction;
private final List<Column> referencedColumns = new ArrayList<>();
private boolean creationEnabled = true;
@ -90,8 +91,8 @@ public class ForeignKey extends Constraint {
isReferenceToPrimaryKey()
);
return cascadeDeleteEnabled && dialect.supportsCascadeDelete()
? result + " on delete cascade"
return onDeleteAction != null && onDeleteAction != OnDeleteAction.NO_ACTION && dialect.supportsCascadeDelete()
? result + " on delete " + onDeleteAction.toSqlString()
: result;
}
@ -166,12 +167,28 @@ public class ForeignKey extends Constraint {
this.keyDefinition = keyDefinition;
}
public boolean isCascadeDeleteEnabled() {
return cascadeDeleteEnabled;
public void setOnDeleteAction(OnDeleteAction onDeleteAction) {
this.onDeleteAction = onDeleteAction;
}
public OnDeleteAction getOnDeleteAction() {
return onDeleteAction;
}
/**
* @deprecated use {@link #getOnDeleteAction()}
*/
@Deprecated(since = "6.2")
public boolean isCascadeDeleteEnabled() {
return onDeleteAction == OnDeleteAction.CASCADE;
}
/**
* @deprecated use {@link #setOnDeleteAction(OnDeleteAction)}
*/
@Deprecated(since = "6.2")
public void setCascadeDeleteEnabled(boolean cascadeDeleteEnabled) {
this.cascadeDeleteEnabled = cascadeDeleteEnabled;
this.onDeleteAction = cascadeDeleteEnabled ? OnDeleteAction.CASCADE : OnDeleteAction.NO_ACTION;
}
public boolean isPhysicalConstraint() {

View File

@ -105,7 +105,7 @@ public class ManyToOne extends ToOne {
getForeignKeyDefinition(),
new ArrayList<>( property.getColumns() )
);
fk.setCascadeDeleteEnabled( isCascadeDeleteEnabled() );
fk.setOnDeleteAction( getOnDeleteAction() );
}
}
}

View File

@ -24,6 +24,7 @@ import org.hibernate.FetchMode;
import org.hibernate.MappingException;
import org.hibernate.Remove;
import org.hibernate.TimeZoneStorageStrategy;
import org.hibernate.annotations.OnDeleteAction;
import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.boot.model.convert.internal.ClassBasedConverterDescriptor;
import org.hibernate.boot.model.convert.spi.ConverterDescriptor;
@ -96,7 +97,7 @@ public abstract class SimpleValue implements KeyValue {
private String foreignKeyName;
private String foreignKeyDefinition;
private boolean alternateUniqueKey;
private boolean cascadeDeleteEnabled;
private OnDeleteAction onDeleteAction;
private boolean foreignKeyEnabled = true;
private ConverterDescriptor attributeConverterDescriptor;
@ -130,7 +131,7 @@ public abstract class SimpleValue implements KeyValue {
this.foreignKeyName = original.foreignKeyName;
this.foreignKeyDefinition = original.foreignKeyDefinition;
this.alternateUniqueKey = original.alternateUniqueKey;
this.cascadeDeleteEnabled = original.cascadeDeleteEnabled;
this.onDeleteAction = original.onDeleteAction;
this.attributeConverterDescriptor = original.attributeConverterDescriptor;
this.type = original.type;
this.customIdGeneratorCreator = original.customIdGeneratorCreator;
@ -150,15 +151,32 @@ public abstract class SimpleValue implements KeyValue {
return getMetadata().getMetadataBuildingOptions().getServiceRegistry();
}
@Override
public boolean isCascadeDeleteEnabled() {
return cascadeDeleteEnabled;
public void setOnDeleteAction(OnDeleteAction onDeleteAction) {
this.onDeleteAction = onDeleteAction;
}
public void setCascadeDeleteEnabled(boolean cascadeDeleteEnabled) {
this.cascadeDeleteEnabled = cascadeDeleteEnabled;
public OnDeleteAction getOnDeleteAction() {
return onDeleteAction;
}
/**
* @deprecated use {@link #getOnDeleteAction()}
*/
@Deprecated(since = "6.2")
@Override
public boolean isCascadeDeleteEnabled() {
return onDeleteAction == OnDeleteAction.CASCADE;
}
/**
* @deprecated use {@link #setOnDeleteAction(OnDeleteAction)}
*/
@Deprecated(since = "6.2")
public void setCascadeDeleteEnabled(boolean cascadeDeleteEnabled) {
this.onDeleteAction = cascadeDeleteEnabled ? OnDeleteAction.CASCADE : OnDeleteAction.NO_ACTION;
}
public void addColumn(Column column) {
addColumn( column, true, true );
}
@ -325,7 +343,7 @@ public abstract class SimpleValue implements KeyValue {
public ForeignKey createForeignKeyOfEntity(String entityName) {
if ( isConstrained() ) {
final ForeignKey fk = table.createForeignKey( getForeignKeyName(), getConstraintColumns(), entityName, getForeignKeyDefinition() );
fk.setCascadeDeleteEnabled( cascadeDeleteEnabled );
fk.setOnDeleteAction( onDeleteAction );
return fk;
}

View File

@ -10,6 +10,7 @@ import java.util.List;
import java.util.Locale;
import org.hibernate.AssertionFailure;
import org.hibernate.annotations.OnDeleteAction;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.model.relational.SqlStringGenerationContext;
import org.hibernate.dialect.Dialect;
@ -77,8 +78,9 @@ public class StandardForeignKeyExporter implements Exporter<ForeignKey> {
);
if ( dialect.supportsCascadeDelete() ) {
if ( foreignKey.isCascadeDeleteEnabled() ) {
buffer.append( " on delete cascade" );
OnDeleteAction onDeleteAction = foreignKey.getOnDeleteAction();
if ( onDeleteAction != null && onDeleteAction != OnDeleteAction.NO_ACTION ) {
buffer.append( " on delete " ).append( onDeleteAction.toSqlString() );
}
}