HHH-11180 - JPA @ForeignKey still not consistently applied from annotation binding
- Fix ForeignKey support for PrimaryKeyJoinColumn / PrimaryKeyJoinColumns - Fix ForeignKey support for JoinColumn / JoinColumns - Fix ForeignKey support for JoinTable when applying value NO_CONSTRAINT. - Fix ForeignKey support for MapKeyJoinColumn / MapKeyJoinColumns - Fix ForeignKey support for AssociationOverride / AssociationOverrides
This commit is contained in:
parent
15b0a683f2
commit
aeb3aee626
|
@ -15,6 +15,7 @@ import javax.persistence.AttributeOverrides;
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.Embeddable;
|
import javax.persistence.Embeddable;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.ForeignKey;
|
||||||
import javax.persistence.JoinColumn;
|
import javax.persistence.JoinColumn;
|
||||||
import javax.persistence.JoinTable;
|
import javax.persistence.JoinTable;
|
||||||
import javax.persistence.MappedSuperclass;
|
import javax.persistence.MappedSuperclass;
|
||||||
|
@ -48,6 +49,8 @@ public abstract class AbstractPropertyHolder implements PropertyHolder {
|
||||||
private Map<String, JoinColumn[]> currentPropertyJoinColumnOverride;
|
private Map<String, JoinColumn[]> currentPropertyJoinColumnOverride;
|
||||||
private Map<String, JoinTable> holderJoinTableOverride;
|
private Map<String, JoinTable> holderJoinTableOverride;
|
||||||
private Map<String, JoinTable> currentPropertyJoinTableOverride;
|
private Map<String, JoinTable> currentPropertyJoinTableOverride;
|
||||||
|
private Map<String, ForeignKey> holderForeignKeyOverride;
|
||||||
|
private Map<String, ForeignKey> currentPropertyForeignKeyOverride;
|
||||||
private String path;
|
private String path;
|
||||||
private MetadataBuildingContext context;
|
private MetadataBuildingContext context;
|
||||||
private Boolean isInIdClass;
|
private Boolean isInIdClass;
|
||||||
|
@ -170,29 +173,28 @@ public abstract class AbstractPropertyHolder implements PropertyHolder {
|
||||||
this.currentPropertyColumnOverride = null;
|
this.currentPropertyColumnOverride = null;
|
||||||
this.currentPropertyJoinColumnOverride = null;
|
this.currentPropertyJoinColumnOverride = null;
|
||||||
this.currentPropertyJoinTableOverride = null;
|
this.currentPropertyJoinTableOverride = null;
|
||||||
|
this.currentPropertyForeignKeyOverride = null;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.currentPropertyColumnOverride = buildColumnOverride(
|
this.currentPropertyColumnOverride = buildColumnOverride( property, getPath() );
|
||||||
property,
|
|
||||||
getPath()
|
|
||||||
);
|
|
||||||
if ( this.currentPropertyColumnOverride.size() == 0 ) {
|
if ( this.currentPropertyColumnOverride.size() == 0 ) {
|
||||||
this.currentPropertyColumnOverride = null;
|
this.currentPropertyColumnOverride = null;
|
||||||
}
|
}
|
||||||
this.currentPropertyJoinColumnOverride = buildJoinColumnOverride(
|
|
||||||
property,
|
this.currentPropertyJoinColumnOverride = buildJoinColumnOverride( property, getPath() );
|
||||||
getPath()
|
|
||||||
);
|
|
||||||
if ( this.currentPropertyJoinColumnOverride.size() == 0 ) {
|
if ( this.currentPropertyJoinColumnOverride.size() == 0 ) {
|
||||||
this.currentPropertyJoinColumnOverride = null;
|
this.currentPropertyJoinColumnOverride = null;
|
||||||
}
|
}
|
||||||
this.currentPropertyJoinTableOverride = buildJoinTableOverride(
|
|
||||||
property,
|
this.currentPropertyJoinTableOverride = buildJoinTableOverride( property, getPath() );
|
||||||
getPath()
|
|
||||||
);
|
|
||||||
if ( this.currentPropertyJoinTableOverride.size() == 0 ) {
|
if ( this.currentPropertyJoinTableOverride.size() == 0 ) {
|
||||||
this.currentPropertyJoinTableOverride = null;
|
this.currentPropertyJoinTableOverride = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.currentPropertyForeignKeyOverride = buildForeignKeyOverride( property, getPath() );
|
||||||
|
if ( this.currentPropertyForeignKeyOverride.size() == 0 ) {
|
||||||
|
this.currentPropertyForeignKeyOverride = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,6 +300,30 @@ public abstract class AbstractPropertyHolder implements PropertyHolder {
|
||||||
return override;
|
return override;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ForeignKey getOverriddenForeignKey(String propertyName) {
|
||||||
|
ForeignKey result = getExactOverriddenForeignKey( propertyName );
|
||||||
|
if ( result == null && propertyName.contains( ".collection&&element." ) ) {
|
||||||
|
//support for non map collections where no prefix is needed
|
||||||
|
//TODO cache the underlying regexp
|
||||||
|
result = getExactOverriddenForeignKey( propertyName.replace( ".collection&&element.", "." ) );
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ForeignKey getExactOverriddenForeignKey(String propertyName) {
|
||||||
|
ForeignKey override = null;
|
||||||
|
if ( parent != null ) {
|
||||||
|
override = parent.getExactOverriddenForeignKey( propertyName );
|
||||||
|
}
|
||||||
|
if ( override == null && currentPropertyForeignKeyOverride != null ) {
|
||||||
|
override = currentPropertyForeignKeyOverride.get( propertyName );
|
||||||
|
}
|
||||||
|
if ( override == null && holderForeignKeyOverride != null ) {
|
||||||
|
override = holderForeignKeyOverride.get( propertyName );
|
||||||
|
}
|
||||||
|
return override;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get column overriding, property first, then parent, then holder
|
* Get column overriding, property first, then parent, then holder
|
||||||
* replace the placeholder 'collection&&element' with nothing
|
* replace the placeholder 'collection&&element' with nothing
|
||||||
|
@ -352,6 +378,7 @@ public abstract class AbstractPropertyHolder implements PropertyHolder {
|
||||||
Map<String, Column[]> columnOverride = new HashMap<String, Column[]>();
|
Map<String, Column[]> columnOverride = new HashMap<String, Column[]>();
|
||||||
Map<String, JoinColumn[]> joinColumnOverride = new HashMap<String, JoinColumn[]>();
|
Map<String, JoinColumn[]> joinColumnOverride = new HashMap<String, JoinColumn[]>();
|
||||||
Map<String, JoinTable> joinTableOverride = new HashMap<String, JoinTable>();
|
Map<String, JoinTable> joinTableOverride = new HashMap<String, JoinTable>();
|
||||||
|
Map<String, ForeignKey> foreignKeyOverride = new HashMap<String, ForeignKey>();
|
||||||
while ( current != null && !context.getBuildingOptions().getReflectionManager().toXClass( Object.class ).equals( current ) ) {
|
while ( current != null && !context.getBuildingOptions().getReflectionManager().toXClass( Object.class ).equals( current ) ) {
|
||||||
if ( current.isAnnotationPresent( Entity.class ) || current.isAnnotationPresent( MappedSuperclass.class )
|
if ( current.isAnnotationPresent( Entity.class ) || current.isAnnotationPresent( MappedSuperclass.class )
|
||||||
|| current.isAnnotationPresent( Embeddable.class ) ) {
|
|| current.isAnnotationPresent( Embeddable.class ) ) {
|
||||||
|
@ -359,12 +386,15 @@ public abstract class AbstractPropertyHolder implements PropertyHolder {
|
||||||
Map<String, Column[]> currentOverride = buildColumnOverride( current, getPath() );
|
Map<String, Column[]> currentOverride = buildColumnOverride( current, getPath() );
|
||||||
Map<String, JoinColumn[]> currentJoinOverride = buildJoinColumnOverride( current, getPath() );
|
Map<String, JoinColumn[]> currentJoinOverride = buildJoinColumnOverride( current, getPath() );
|
||||||
Map<String, JoinTable> currentJoinTableOverride = buildJoinTableOverride( current, getPath() );
|
Map<String, JoinTable> currentJoinTableOverride = buildJoinTableOverride( current, getPath() );
|
||||||
|
Map<String, ForeignKey> currentForeignKeyOverride = buildForeignKeyOverride( current, getPath() );
|
||||||
currentOverride.putAll( columnOverride ); //subclasses have precedence over superclasses
|
currentOverride.putAll( columnOverride ); //subclasses have precedence over superclasses
|
||||||
currentJoinOverride.putAll( joinColumnOverride ); //subclasses have precedence over superclasses
|
currentJoinOverride.putAll( joinColumnOverride ); //subclasses have precedence over superclasses
|
||||||
currentJoinTableOverride.putAll( joinTableOverride ); //subclasses have precedence over superclasses
|
currentJoinTableOverride.putAll( joinTableOverride ); //subclasses have precedence over superclasses
|
||||||
|
currentForeignKeyOverride.putAll( foreignKeyOverride ); //subclasses have precedence over superclasses
|
||||||
columnOverride = currentOverride;
|
columnOverride = currentOverride;
|
||||||
joinColumnOverride = currentJoinOverride;
|
joinColumnOverride = currentJoinOverride;
|
||||||
joinTableOverride = currentJoinTableOverride;
|
joinTableOverride = currentJoinTableOverride;
|
||||||
|
foreignKeyOverride = currentForeignKeyOverride;
|
||||||
}
|
}
|
||||||
current = current.getSuperclass();
|
current = current.getSuperclass();
|
||||||
}
|
}
|
||||||
|
@ -372,31 +402,32 @@ public abstract class AbstractPropertyHolder implements PropertyHolder {
|
||||||
holderColumnOverride = columnOverride.size() > 0 ? columnOverride : null;
|
holderColumnOverride = columnOverride.size() > 0 ? columnOverride : null;
|
||||||
holderJoinColumnOverride = joinColumnOverride.size() > 0 ? joinColumnOverride : null;
|
holderJoinColumnOverride = joinColumnOverride.size() > 0 ? joinColumnOverride : null;
|
||||||
holderJoinTableOverride = joinTableOverride.size() > 0 ? joinTableOverride : null;
|
holderJoinTableOverride = joinTableOverride.size() > 0 ? joinTableOverride : null;
|
||||||
|
holderForeignKeyOverride = foreignKeyOverride.size() > 0 ? foreignKeyOverride : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<String, Column[]> buildColumnOverride(XAnnotatedElement element, String path) {
|
private static Map<String, Column[]> buildColumnOverride(XAnnotatedElement element, String path) {
|
||||||
Map<String, Column[]> columnOverride = new HashMap<String, Column[]>();
|
Map<String, Column[]> columnOverride = new HashMap<String, Column[]>();
|
||||||
if ( element == null ) return columnOverride;
|
if ( element != null ) {
|
||||||
AttributeOverride singleOverride = element.getAnnotation( AttributeOverride.class );
|
AttributeOverride singleOverride = element.getAnnotation( AttributeOverride.class );
|
||||||
AttributeOverrides multipleOverrides = element.getAnnotation( AttributeOverrides.class );
|
AttributeOverrides multipleOverrides = element.getAnnotation( AttributeOverrides.class );
|
||||||
AttributeOverride[] overrides;
|
AttributeOverride[] overrides;
|
||||||
if ( singleOverride != null ) {
|
if ( singleOverride != null ) {
|
||||||
overrides = new AttributeOverride[] { singleOverride };
|
overrides = new AttributeOverride[]{ singleOverride };
|
||||||
}
|
}
|
||||||
else if ( multipleOverrides != null ) {
|
else if ( multipleOverrides != null ) {
|
||||||
overrides = multipleOverrides.value();
|
overrides = multipleOverrides.value();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
overrides = null;
|
overrides = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
//fill overridden columns
|
if ( overrides != null ) {
|
||||||
if ( overrides != null ) {
|
for ( AttributeOverride depAttr : overrides ) {
|
||||||
for (AttributeOverride depAttr : overrides) {
|
columnOverride.put(
|
||||||
columnOverride.put(
|
StringHelper.qualify( path, depAttr.name() ),
|
||||||
StringHelper.qualify( path, depAttr.name() ),
|
new Column[]{ depAttr.column() }
|
||||||
new Column[] { depAttr.column() }
|
);
|
||||||
);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return columnOverride;
|
return columnOverride;
|
||||||
|
@ -404,56 +435,62 @@ public abstract class AbstractPropertyHolder implements PropertyHolder {
|
||||||
|
|
||||||
private static Map<String, JoinColumn[]> buildJoinColumnOverride(XAnnotatedElement element, String path) {
|
private static Map<String, JoinColumn[]> buildJoinColumnOverride(XAnnotatedElement element, String path) {
|
||||||
Map<String, JoinColumn[]> columnOverride = new HashMap<String, JoinColumn[]>();
|
Map<String, JoinColumn[]> columnOverride = new HashMap<String, JoinColumn[]>();
|
||||||
if ( element == null ) return columnOverride;
|
if ( element != null ) {
|
||||||
AssociationOverride singleOverride = element.getAnnotation( AssociationOverride.class );
|
AssociationOverride[] overrides = buildAssociationOverrides( element, path );
|
||||||
AssociationOverrides multipleOverrides = element.getAnnotation( AssociationOverrides.class );
|
if ( overrides != null ) {
|
||||||
AssociationOverride[] overrides;
|
for ( AssociationOverride depAttr : overrides ) {
|
||||||
if ( singleOverride != null ) {
|
columnOverride.put(
|
||||||
overrides = new AssociationOverride[] { singleOverride };
|
StringHelper.qualify( path, depAttr.name() ),
|
||||||
}
|
depAttr.joinColumns()
|
||||||
else if ( multipleOverrides != null ) {
|
);
|
||||||
overrides = multipleOverrides.value();
|
}
|
||||||
}
|
|
||||||
else {
|
|
||||||
overrides = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
//fill overridden columns
|
|
||||||
if ( overrides != null ) {
|
|
||||||
for (AssociationOverride depAttr : overrides) {
|
|
||||||
columnOverride.put(
|
|
||||||
StringHelper.qualify( path, depAttr.name() ),
|
|
||||||
depAttr.joinColumns()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return columnOverride;
|
return columnOverride;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<String, JoinTable> buildJoinTableOverride(XAnnotatedElement element, String path) {
|
private static Map<String, ForeignKey> buildForeignKeyOverride(XAnnotatedElement element, String path) {
|
||||||
Map<String, JoinTable> tableOverride = new HashMap<String, JoinTable>();
|
Map<String, ForeignKey> foreignKeyOverride = new HashMap<String, ForeignKey>();
|
||||||
if ( element == null ) return tableOverride;
|
if ( element != null ) {
|
||||||
|
AssociationOverride[] overrides = buildAssociationOverrides( element, path );
|
||||||
|
if ( overrides != null ) {
|
||||||
|
for ( AssociationOverride depAttr : overrides ) {
|
||||||
|
foreignKeyOverride.put( StringHelper.qualify( path, depAttr.name() ), depAttr.foreignKey() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return foreignKeyOverride;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AssociationOverride[] buildAssociationOverrides(XAnnotatedElement element, String path) {
|
||||||
AssociationOverride singleOverride = element.getAnnotation( AssociationOverride.class );
|
AssociationOverride singleOverride = element.getAnnotation( AssociationOverride.class );
|
||||||
AssociationOverrides multipleOverrides = element.getAnnotation( AssociationOverrides.class );
|
AssociationOverrides pluralOverrides = element.getAnnotation( AssociationOverrides.class );
|
||||||
|
|
||||||
AssociationOverride[] overrides;
|
AssociationOverride[] overrides;
|
||||||
if ( singleOverride != null ) {
|
if ( singleOverride != null ) {
|
||||||
overrides = new AssociationOverride[] { singleOverride };
|
overrides = new AssociationOverride[] { singleOverride };
|
||||||
}
|
}
|
||||||
else if ( multipleOverrides != null ) {
|
else if ( pluralOverrides != null ) {
|
||||||
overrides = multipleOverrides.value();
|
overrides = pluralOverrides.value();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
overrides = null;
|
overrides = null;
|
||||||
}
|
}
|
||||||
|
return overrides;
|
||||||
|
}
|
||||||
|
|
||||||
//fill overridden tables
|
private static Map<String, JoinTable> buildJoinTableOverride(XAnnotatedElement element, String path) {
|
||||||
if ( overrides != null ) {
|
Map<String, JoinTable> tableOverride = new HashMap<String, JoinTable>();
|
||||||
for (AssociationOverride depAttr : overrides) {
|
if ( element != null ) {
|
||||||
if ( depAttr.joinColumns().length == 0 ) {
|
AssociationOverride[] overrides = buildAssociationOverrides( element, path );
|
||||||
tableOverride.put(
|
if ( overrides != null ) {
|
||||||
StringHelper.qualify( path, depAttr.name() ),
|
for ( AssociationOverride depAttr : overrides ) {
|
||||||
depAttr.joinTable()
|
if ( depAttr.joinColumns().length == 0 ) {
|
||||||
);
|
tableOverride.put(
|
||||||
|
StringHelper.qualify( path, depAttr.name() ),
|
||||||
|
depAttr.joinTable()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -657,8 +657,20 @@ public final class AnnotationBinder {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
final PrimaryKeyJoinColumn pkJoinColumn = clazzToProcess.getAnnotation( PrimaryKeyJoinColumn.class );
|
final PrimaryKeyJoinColumn pkJoinColumn = clazzToProcess.getAnnotation( PrimaryKeyJoinColumn.class );
|
||||||
if ( pkJoinColumn != null && pkJoinColumn.foreignKey() != null
|
final PrimaryKeyJoinColumns pkJoinColumns = clazzToProcess.getAnnotation( PrimaryKeyJoinColumns.class );
|
||||||
&& !StringHelper.isEmpty( pkJoinColumn.foreignKey().name() ) ) {
|
|
||||||
|
if ( pkJoinColumns != null && pkJoinColumns.foreignKey().value() == ConstraintMode.NO_CONSTRAINT ) {
|
||||||
|
// don't apply a constraint based on ConstraintMode
|
||||||
|
key.setForeignKeyName( "none" );
|
||||||
|
}
|
||||||
|
else if ( pkJoinColumns != null && !StringHelper.isEmpty( pkJoinColumns.foreignKey().name() ) ) {
|
||||||
|
key.setForeignKeyName( pkJoinColumns.foreignKey().name() );
|
||||||
|
}
|
||||||
|
else if ( pkJoinColumn != null && pkJoinColumn.foreignKey().value() == ConstraintMode.NO_CONSTRAINT ) {
|
||||||
|
// don't apply a constraint based on ConstraintMode
|
||||||
|
key.setForeignKeyName( "none" );
|
||||||
|
}
|
||||||
|
else if ( pkJoinColumn != null && !StringHelper.isEmpty( pkJoinColumn.foreignKey().name() ) ) {
|
||||||
key.setForeignKeyName( pkJoinColumn.foreignKey().name() );
|
key.setForeignKeyName( pkJoinColumn.foreignKey().name() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2914,6 +2926,7 @@ public final class AnnotationBinder {
|
||||||
}
|
}
|
||||||
|
|
||||||
final JoinColumn joinColumn = property.getAnnotation( JoinColumn.class );
|
final JoinColumn joinColumn = property.getAnnotation( JoinColumn.class );
|
||||||
|
final JoinColumns joinColumns = property.getAnnotation( JoinColumns.class );
|
||||||
|
|
||||||
//Make sure that JPA1 key-many-to-one columns are read only tooj
|
//Make sure that JPA1 key-many-to-one columns are read only tooj
|
||||||
boolean hasSpecjManyToOne=false;
|
boolean hasSpecjManyToOne=false;
|
||||||
|
@ -2942,8 +2955,8 @@ public final class AnnotationBinder {
|
||||||
final String propertyName = inferredData.getPropertyName();
|
final String propertyName = inferredData.getPropertyName();
|
||||||
value.setTypeUsingReflection( propertyHolder.getClassName(), propertyName );
|
value.setTypeUsingReflection( propertyHolder.getClassName(), propertyName );
|
||||||
|
|
||||||
if ( joinColumn != null
|
if ( ( joinColumn != null && joinColumn.foreignKey().value() == ConstraintMode.NO_CONSTRAINT )
|
||||||
&& joinColumn.foreignKey().value() == ConstraintMode.NO_CONSTRAINT ) {
|
|| ( joinColumns != null && joinColumns.foreignKey().value() == ConstraintMode.NO_CONSTRAINT ) ) {
|
||||||
// not ideal...
|
// not ideal...
|
||||||
value.setForeignKeyName( "none" );
|
value.setForeignKeyName( "none" );
|
||||||
}
|
}
|
||||||
|
@ -2952,9 +2965,25 @@ public final class AnnotationBinder {
|
||||||
if ( fk != null && StringHelper.isNotEmpty( fk.name() ) ) {
|
if ( fk != null && StringHelper.isNotEmpty( fk.name() ) ) {
|
||||||
value.setForeignKeyName( fk.name() );
|
value.setForeignKeyName( fk.name() );
|
||||||
}
|
}
|
||||||
else if ( joinColumn != null ) {
|
else {
|
||||||
value.setForeignKeyName( StringHelper.nullIfEmpty( joinColumn.foreignKey().name() ) );
|
final javax.persistence.ForeignKey fkOverride = propertyHolder.getOverriddenForeignKey(
|
||||||
value.setForeignKeyDefinition( StringHelper.nullIfEmpty( joinColumn.foreignKey().foreignKeyDefinition() ) );
|
StringHelper.qualify( propertyHolder.getPath(), propertyName )
|
||||||
|
);
|
||||||
|
if ( fkOverride != null && fkOverride.value() == ConstraintMode.NO_CONSTRAINT ) {
|
||||||
|
value.setForeignKeyName( "none" );
|
||||||
|
}
|
||||||
|
else if ( fkOverride != null ) {
|
||||||
|
value.setForeignKeyName( StringHelper.nullIfEmpty( fkOverride.name() ) );
|
||||||
|
value.setForeignKeyDefinition( StringHelper.nullIfEmpty( fkOverride.foreignKeyDefinition() ) );
|
||||||
|
}
|
||||||
|
else if ( joinColumns != null ) {
|
||||||
|
value.setForeignKeyName( StringHelper.nullIfEmpty( joinColumns.foreignKey().name() ) );
|
||||||
|
value.setForeignKeyDefinition( StringHelper.nullIfEmpty( joinColumns.foreignKey().foreignKeyDefinition() ) );
|
||||||
|
}
|
||||||
|
else if ( joinColumn != null ) {
|
||||||
|
value.setForeignKeyName( StringHelper.nullIfEmpty( joinColumn.foreignKey().name() ) );
|
||||||
|
value.setForeignKeyDefinition( StringHelper.nullIfEmpty( joinColumn.foreignKey().foreignKeyDefinition() ) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
package org.hibernate.cfg;
|
package org.hibernate.cfg;
|
||||||
|
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.ForeignKey;
|
||||||
import javax.persistence.JoinColumn;
|
import javax.persistence.JoinColumn;
|
||||||
import javax.persistence.JoinTable;
|
import javax.persistence.JoinTable;
|
||||||
|
|
||||||
|
@ -67,6 +68,14 @@ public interface PropertyHolder {
|
||||||
*/
|
*/
|
||||||
JoinColumn[] getOverriddenJoinColumn(String propertyName);
|
JoinColumn[] getOverriddenJoinColumn(String propertyName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return null if hte foreign key is not overridden, or the foreign key if true
|
||||||
|
*/
|
||||||
|
default ForeignKey getOverriddenForeignKey(String propertyName) {
|
||||||
|
// todo: does this necessarily need to be a default method?
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* return
|
* return
|
||||||
* - null if no join table is present,
|
* - null if no join table is present,
|
||||||
|
|
|
@ -868,7 +868,7 @@ public abstract class CollectionBinder {
|
||||||
LOG.debugf( "Mapping collection: %s -> %s", collection.getRole(), collection.getCollectionTable().getName() );
|
LOG.debugf( "Mapping collection: %s -> %s", collection.getRole(), collection.getCollectionTable().getName() );
|
||||||
}
|
}
|
||||||
bindFilters( false );
|
bindFilters( false );
|
||||||
bindCollectionSecondPass( collection, null, fkJoinColumns, cascadeDeleteEnabled, property, buildingContext );
|
bindCollectionSecondPass( collection, null, fkJoinColumns, cascadeDeleteEnabled, property, propertyHolder, buildingContext );
|
||||||
if ( !collection.isInverse()
|
if ( !collection.isInverse()
|
||||||
&& !collection.getKey().isNullable() ) {
|
&& !collection.getKey().isNullable() ) {
|
||||||
// for non-inverse one-to-many, with a not-null fk, add a backref!
|
// for non-inverse one-to-many, with a not-null fk, add a backref!
|
||||||
|
@ -1085,6 +1085,7 @@ public abstract class CollectionBinder {
|
||||||
Ejb3JoinColumn[] joinColumns,
|
Ejb3JoinColumn[] joinColumns,
|
||||||
boolean cascadeDeleteEnabled,
|
boolean cascadeDeleteEnabled,
|
||||||
XProperty property,
|
XProperty property,
|
||||||
|
PropertyHolder propertyHolder,
|
||||||
MetadataBuildingContext buildingContext) {
|
MetadataBuildingContext buildingContext) {
|
||||||
//binding key reference using column
|
//binding key reference using column
|
||||||
KeyValue keyVal;
|
KeyValue keyVal;
|
||||||
|
@ -1160,14 +1161,26 @@ public abstract class CollectionBinder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
final JoinColumn joinColumnAnn = property.getAnnotation( JoinColumn.class );
|
final javax.persistence.ForeignKey fkOverride = propertyHolder.getOverriddenForeignKey(
|
||||||
if ( joinColumnAnn != null ) {
|
StringHelper.qualify( propertyHolder.getPath(), property.getName() )
|
||||||
if ( joinColumnAnn.foreignKey().value() == ConstraintMode.NO_CONSTRAINT ) {
|
);
|
||||||
key.setForeignKeyName( "none" );
|
if ( fkOverride != null && fkOverride.value() == ConstraintMode.NO_CONSTRAINT ) {
|
||||||
}
|
key.setForeignKeyName( "none" );
|
||||||
else {
|
}
|
||||||
key.setForeignKeyName( StringHelper.nullIfEmpty( joinColumnAnn.foreignKey().name() ) );
|
else if ( fkOverride != null ) {
|
||||||
key.setForeignKeyDefinition( StringHelper.nullIfEmpty( joinColumnAnn.foreignKey().foreignKeyDefinition() ) );
|
key.setForeignKeyName( StringHelper.nullIfEmpty( fkOverride.name() ) );
|
||||||
|
key.setForeignKeyDefinition( StringHelper.nullIfEmpty( fkOverride.foreignKeyDefinition() ) );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final JoinColumn joinColumnAnn = property.getAnnotation( JoinColumn.class );
|
||||||
|
if ( joinColumnAnn != null ) {
|
||||||
|
if ( joinColumnAnn.foreignKey().value() == ConstraintMode.NO_CONSTRAINT ) {
|
||||||
|
key.setForeignKeyName( "none" );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
key.setForeignKeyName( StringHelper.nullIfEmpty( joinColumnAnn.foreignKey().name() ) );
|
||||||
|
key.setForeignKeyDefinition( StringHelper.nullIfEmpty( joinColumnAnn.foreignKey().foreignKeyDefinition() ) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1319,7 +1332,7 @@ public abstract class CollectionBinder {
|
||||||
collValue.setCollectionTable( associationTableBinder.bind() );
|
collValue.setCollectionTable( associationTableBinder.bind() );
|
||||||
}
|
}
|
||||||
bindFilters( isCollectionOfEntities );
|
bindFilters( isCollectionOfEntities );
|
||||||
bindCollectionSecondPass( collValue, collectionEntity, joinColumns, cascadeDeleteEnabled, property, buildingContext );
|
bindCollectionSecondPass( collValue, collectionEntity, joinColumns, cascadeDeleteEnabled, property, propertyHolder, buildingContext );
|
||||||
|
|
||||||
ManyToOne element = null;
|
ManyToOne element = null;
|
||||||
if ( isCollectionOfEntities ) {
|
if ( isCollectionOfEntities ) {
|
||||||
|
@ -1348,7 +1361,7 @@ public abstract class CollectionBinder {
|
||||||
if ( joinTableAnn != null ) {
|
if ( joinTableAnn != null ) {
|
||||||
String foreignKeyName = joinTableAnn.inverseForeignKey().name();
|
String foreignKeyName = joinTableAnn.inverseForeignKey().name();
|
||||||
String foreignKeyDefinition = joinTableAnn.inverseForeignKey().foreignKeyDefinition();
|
String foreignKeyDefinition = joinTableAnn.inverseForeignKey().foreignKeyDefinition();
|
||||||
ConstraintMode foreignKeyValue = joinTableAnn.foreignKey().value();
|
ConstraintMode foreignKeyValue = joinTableAnn.inverseForeignKey().value();
|
||||||
if ( joinTableAnn.inverseJoinColumns().length != 0 ) {
|
if ( joinTableAnn.inverseJoinColumns().length != 0 ) {
|
||||||
final JoinColumn joinColumnAnn = joinTableAnn.inverseJoinColumns()[0];
|
final JoinColumn joinColumnAnn = joinTableAnn.inverseJoinColumns()[0];
|
||||||
if ( "".equals( foreignKeyName ) ) {
|
if ( "".equals( foreignKeyName ) ) {
|
||||||
|
@ -1359,7 +1372,7 @@ public abstract class CollectionBinder {
|
||||||
foreignKeyValue = joinColumnAnn.foreignKey().value();
|
foreignKeyValue = joinColumnAnn.foreignKey().value();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( joinTableAnn.foreignKey().value() == ConstraintMode.NO_CONSTRAINT ) {
|
if ( joinTableAnn.inverseForeignKey().value() == ConstraintMode.NO_CONSTRAINT ) {
|
||||||
element.setForeignKeyName( "none" );
|
element.setForeignKeyName( "none" );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -1575,6 +1588,7 @@ public abstract class CollectionBinder {
|
||||||
Ejb3JoinColumn[] joinColumns,
|
Ejb3JoinColumn[] joinColumns,
|
||||||
boolean cascadeDeleteEnabled,
|
boolean cascadeDeleteEnabled,
|
||||||
XProperty property,
|
XProperty property,
|
||||||
|
PropertyHolder propertyHolder,
|
||||||
MetadataBuildingContext buildingContext) {
|
MetadataBuildingContext buildingContext) {
|
||||||
try {
|
try {
|
||||||
BinderHelper.createSyntheticPropertyReference(
|
BinderHelper.createSyntheticPropertyReference(
|
||||||
|
@ -1589,7 +1603,7 @@ public abstract class CollectionBinder {
|
||||||
catch (AnnotationException ex) {
|
catch (AnnotationException ex) {
|
||||||
throw new AnnotationException( "Unable to map collection " + collValue.getOwner().getClassName() + "." + property.getName(), ex );
|
throw new AnnotationException( "Unable to map collection " + collValue.getOwner().getClassName() + "." + property.getName(), ex );
|
||||||
}
|
}
|
||||||
SimpleValue key = buildCollectionKey( collValue, joinColumns, cascadeDeleteEnabled, property, buildingContext );
|
SimpleValue key = buildCollectionKey( collValue, joinColumns, cascadeDeleteEnabled, property, propertyHolder, buildingContext );
|
||||||
if ( property.isAnnotationPresent( ElementCollection.class ) && joinColumns.length > 0 ) {
|
if ( property.isAnnotationPresent( ElementCollection.class ) && joinColumns.length > 0 ) {
|
||||||
joinColumns[0].setJPA2ElementCollection( true );
|
joinColumns[0].setJPA2ElementCollection( true );
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,8 +12,11 @@ import java.util.Map;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import javax.persistence.AttributeOverride;
|
import javax.persistence.AttributeOverride;
|
||||||
import javax.persistence.AttributeOverrides;
|
import javax.persistence.AttributeOverrides;
|
||||||
|
import javax.persistence.ConstraintMode;
|
||||||
import javax.persistence.InheritanceType;
|
import javax.persistence.InheritanceType;
|
||||||
import javax.persistence.MapKeyClass;
|
import javax.persistence.MapKeyClass;
|
||||||
|
import javax.persistence.MapKeyJoinColumn;
|
||||||
|
import javax.persistence.MapKeyJoinColumns;
|
||||||
|
|
||||||
import org.hibernate.AnnotationException;
|
import org.hibernate.AnnotationException;
|
||||||
import org.hibernate.AssertionFailure;
|
import org.hibernate.AssertionFailure;
|
||||||
|
@ -294,6 +297,20 @@ public class MapBinder extends CollectionBinder {
|
||||||
col.forceNotNull();
|
col.forceNotNull();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( element != null ) {
|
||||||
|
final javax.persistence.ForeignKey foreignKey = getMapKeyForeignKey( property );
|
||||||
|
if ( foreignKey != null ) {
|
||||||
|
if ( foreignKey.value() == ConstraintMode.NO_CONSTRAINT ) {
|
||||||
|
element.setForeignKeyName( "none" );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
element.setForeignKeyName( StringHelper.nullIfEmpty( foreignKey.name() ) );
|
||||||
|
element.setForeignKeyDefinition( StringHelper.nullIfEmpty( foreignKey.foreignKeyDefinition() ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ( isIndexOfEntities ) {
|
if ( isIndexOfEntities ) {
|
||||||
bindManytoManyInverseFk(
|
bindManytoManyInverseFk(
|
||||||
collectionEntity,
|
collectionEntity,
|
||||||
|
@ -306,6 +323,20 @@ public class MapBinder extends CollectionBinder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private javax.persistence.ForeignKey getMapKeyForeignKey(XProperty property) {
|
||||||
|
final MapKeyJoinColumns mapKeyJoinColumns = property.getAnnotation( MapKeyJoinColumns.class );
|
||||||
|
if ( mapKeyJoinColumns != null ) {
|
||||||
|
return mapKeyJoinColumns.foreignKey();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final MapKeyJoinColumn mapKeyJoinColumn = property.getAnnotation( MapKeyJoinColumn.class );
|
||||||
|
if ( mapKeyJoinColumn != null ) {
|
||||||
|
return mapKeyJoinColumn.foreignKey();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean mappingDefinedAttributeOverrideOnMapKey(XProperty property) {
|
private boolean mappingDefinedAttributeOverrideOnMapKey(XProperty property) {
|
||||||
if ( property.isAnnotationPresent( AttributeOverride.class ) ) {
|
if ( property.isAnnotationPresent( AttributeOverride.class ) ) {
|
||||||
return namedMapKey( property.getAnnotation( AttributeOverride.class ) );
|
return namedMapKey( property.getAnnotation( AttributeOverride.class ) );
|
||||||
|
|
|
@ -0,0 +1,509 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.constraint;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import javax.persistence.AssociationOverride;
|
||||||
|
import javax.persistence.AssociationOverrides;
|
||||||
|
import javax.persistence.CollectionTable;
|
||||||
|
import javax.persistence.ConstraintMode;
|
||||||
|
import javax.persistence.ElementCollection;
|
||||||
|
import javax.persistence.Embeddable;
|
||||||
|
import javax.persistence.Embedded;
|
||||||
|
import javax.persistence.EmbeddedId;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.ForeignKey;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Inheritance;
|
||||||
|
import javax.persistence.InheritanceType;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.JoinColumns;
|
||||||
|
import javax.persistence.JoinTable;
|
||||||
|
import javax.persistence.ManyToMany;
|
||||||
|
import javax.persistence.ManyToOne;
|
||||||
|
import javax.persistence.MapKeyJoinColumn;
|
||||||
|
import javax.persistence.MapKeyJoinColumns;
|
||||||
|
import javax.persistence.MappedSuperclass;
|
||||||
|
import javax.persistence.OneToMany;
|
||||||
|
import javax.persistence.OneToOne;
|
||||||
|
import javax.persistence.PrimaryKeyJoinColumn;
|
||||||
|
import javax.persistence.PrimaryKeyJoinColumns;
|
||||||
|
import javax.persistence.SecondaryTable;
|
||||||
|
|
||||||
|
import org.hibernate.boot.model.relational.Namespace;
|
||||||
|
import org.hibernate.mapping.Column;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Christian Beikov
|
||||||
|
*/
|
||||||
|
@TestForIssue( jiraKey = "HHH-11180" )
|
||||||
|
public class ForeignKeyConstraintTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class<?>[] {
|
||||||
|
CreditCard.class,
|
||||||
|
Person.class,
|
||||||
|
Student.class,
|
||||||
|
Professor.class,
|
||||||
|
Vehicle.class,
|
||||||
|
VehicleBuyInfo.class,
|
||||||
|
Car.class,
|
||||||
|
Truck.class,
|
||||||
|
Company.class
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testJoinColumn() {
|
||||||
|
assertForeignKey( "FK_CAR_OWNER", "OWNER_PERSON_ID" );
|
||||||
|
assertForeignKey( "FK_CAR_OWNER3", "OWNER_PERSON_ID3" );
|
||||||
|
assertForeignKey( "FK_PERSON_CC", "PERSON_CC_ID" );
|
||||||
|
assertNoForeignKey( "FK_CAR_OWNER2", "OWNER_PERSON_ID2" );
|
||||||
|
assertNoForeignKey( "FK_CAR_OWNER4", "OWNER_PERSON_ID4" );
|
||||||
|
assertNoForeignKey( "FK_PERSON_CC2", "PERSON_CC_ID2" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testJoinColumns() {
|
||||||
|
assertForeignKey( "FK_STUDENT_CAR", "CAR_NR", "CAR_VENDOR_NR" );
|
||||||
|
assertForeignKey( "FK_STUDENT_CAR3", "CAR_NR3", "CAR_VENDOR_NR3" );
|
||||||
|
assertNoForeignKey( "FK_STUDENT_CAR2", "CAR_NR2", "CAR_VENDOR_NR2" );
|
||||||
|
assertNoForeignKey( "FK_STUDENT_CAR4", "CAR_NR4", "CAR_VENDOR_NR4" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testJoinTable() {
|
||||||
|
assertForeignKey( "FK_VEHICLE_BUY_INFOS_STUDENT", "STUDENT_ID" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testJoinTableInverse() {
|
||||||
|
assertForeignKey( "FK_VEHICLE_BUY_INFOS_VEHICLE_BUY_INFO", "VEHICLE_BUY_INFO_ID" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPrimaryKeyJoinColumn() {
|
||||||
|
assertForeignKey( "FK_STUDENT_PERSON", "PERSON_ID" );
|
||||||
|
assertNoForeignKey( "FK_PROFESSOR_PERSON", "PERSON_ID" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPrimaryKeyJoinColumns() {
|
||||||
|
assertForeignKey( "FK_CAR_VEHICLE", "CAR_NR", "VENDOR_NR" );
|
||||||
|
assertNoForeignKey( "FK_TRUCK_VEHICLE", "CAR_NR", "VENDOR_NR" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCollectionTable() {
|
||||||
|
assertForeignKey( "FK_OWNER_INFO_CAR", "CAR_NR", "VENDOR_NR" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMapKeyJoinColumn() {
|
||||||
|
assertForeignKey( "FK_OWNER_INFO_PERSON", "PERSON_ID" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMapKeyJoinColumns() {
|
||||||
|
assertForeignKey( "FK_VEHICLE_BUY_INFOS_VEHICLE", "VEHICLE_NR", "VEHICLE_VENDOR_NR" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAssociationOverride() {
|
||||||
|
// class level association overrides
|
||||||
|
assertForeignKey( "FK_COMPANY_OWNER", "OWNER_PERSON_ID" );
|
||||||
|
assertForeignKey( "FK_COMPANY_CREDIT_CARD", "CREDIT_CARD_ID" );
|
||||||
|
assertForeignKey( "FK_COMPANY_CREDIT_CARD3", "CREDIT_CARD_ID3" );
|
||||||
|
assertNoForeignKey( "FK_COMPANY_OWNER2", "OWNER_PERSON_ID2" );
|
||||||
|
assertNoForeignKey( "FK_COMPANY_CREDIT_CARD2", "CREDIT_CARD_ID2" );
|
||||||
|
assertNoForeignKey( "FK_COMPANY_CREDIT_CARD4", "CREDIT_CARD_ID4" );
|
||||||
|
|
||||||
|
// embeddable association overrides
|
||||||
|
assertForeignKey( "FK_COMPANY_CARD", "AO_CI_CC_ID" );
|
||||||
|
assertNoForeignKey( "FK_COMPANY_CARD2", "AO_CI_CC_ID2" );
|
||||||
|
assertForeignKey( "FK_COMPANY_CARD3", "AO_CI_CC_ID3" );
|
||||||
|
assertNoForeignKey( "FK_COMPANY_CARD4", "AO_CI_CC_ID4" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSecondaryTable() {
|
||||||
|
assertForeignKey( "FK_CAR_DETAILS_CAR", "CAR_NR", "CAR_VENDOR_NR" );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertForeignKey(String foreignKeyName, String... columns) {
|
||||||
|
Set<String> columnSet = new LinkedHashSet<>( Arrays.asList( columns ) );
|
||||||
|
for ( Namespace namespace : metadata().getDatabase().getNamespaces() ) {
|
||||||
|
for ( org.hibernate.mapping.Table table : namespace.getTables() ) {
|
||||||
|
Iterator<org.hibernate.mapping.ForeignKey> fkItr = table.getForeignKeyIterator();
|
||||||
|
while ( fkItr.hasNext() ) {
|
||||||
|
org.hibernate.mapping.ForeignKey fk = fkItr.next();
|
||||||
|
|
||||||
|
if ( foreignKeyName.equals( fk.getName() ) ) {
|
||||||
|
assertEquals( "ForeignKey column count not like expected", columnSet.size(), fk.getColumnSpan() );
|
||||||
|
List<String> columnNames = fk.getColumns().stream().map(Column::getName).collect(Collectors.toList());
|
||||||
|
assertTrue(
|
||||||
|
"ForeignKey columns [" + columnNames + "] do not match expected columns [" + columnSet + "]",
|
||||||
|
columnSet.containsAll( columnNames )
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fail( "ForeignKey '" + foreignKeyName + "' could not be found!" );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertNoForeignKey(String foreignKeyName, String... columns) {
|
||||||
|
Set<String> columnSet = new LinkedHashSet<>( Arrays.asList( columns ) );
|
||||||
|
for ( Namespace namespace : metadata().getDatabase().getNamespaces() ) {
|
||||||
|
for ( org.hibernate.mapping.Table table : namespace.getTables() ) {
|
||||||
|
Iterator<org.hibernate.mapping.ForeignKey> fkItr = table.getForeignKeyIterator();
|
||||||
|
while ( fkItr.hasNext() ) {
|
||||||
|
org.hibernate.mapping.ForeignKey fk = fkItr.next();
|
||||||
|
assertFalse(
|
||||||
|
"ForeignKey [" + foreignKeyName + "] defined and shouldn't have been.",
|
||||||
|
foreignKeyName.equals( fk.getName() )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "CreditCard")
|
||||||
|
public static class CreditCard {
|
||||||
|
@Id
|
||||||
|
public String number;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Person")
|
||||||
|
@Inheritance( strategy = InheritanceType.JOINED )
|
||||||
|
public static class Person {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
@javax.persistence.Column( nullable = false, unique = true)
|
||||||
|
public long id;
|
||||||
|
|
||||||
|
@OneToMany
|
||||||
|
@JoinColumn(name = "PERSON_CC_ID", foreignKey = @ForeignKey( name = "FK_PERSON_CC" ) )
|
||||||
|
public List<CreditCard> creditCards;
|
||||||
|
|
||||||
|
@OneToMany
|
||||||
|
@JoinColumn(name = "PERSON_CC_ID2", foreignKey = @ForeignKey( name = "FK_PERSON_CC2", value = ConstraintMode.NO_CONSTRAINT ) )
|
||||||
|
public List<CreditCard> creditCards2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Professor")
|
||||||
|
@PrimaryKeyJoinColumn(
|
||||||
|
name = "PERSON_ID",
|
||||||
|
foreignKey = @ForeignKey( name = "FK_PROFESSOR_PERSON", value = ConstraintMode.NO_CONSTRAINT )
|
||||||
|
)
|
||||||
|
public static class Professor extends Person {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Student")
|
||||||
|
@PrimaryKeyJoinColumn( name = "PERSON_ID", foreignKey = @ForeignKey( name = "FK_STUDENT_PERSON" ) )
|
||||||
|
public static class Student extends Person {
|
||||||
|
|
||||||
|
@javax.persistence.Column( name = "MATRICULATION_NUMBER" )
|
||||||
|
public String matriculationNumber;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumns(
|
||||||
|
value = {
|
||||||
|
@JoinColumn( name = "CAR_NR", referencedColumnName = "CAR_NR" ),
|
||||||
|
@JoinColumn( name = "CAR_VENDOR_NR", referencedColumnName = "VENDOR_NR" )
|
||||||
|
},
|
||||||
|
foreignKey = @ForeignKey( name = "FK_STUDENT_CAR" )
|
||||||
|
)
|
||||||
|
public Car car;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumns(
|
||||||
|
value = {
|
||||||
|
@JoinColumn( name = "CAR_NR2", referencedColumnName = "CAR_NR" ),
|
||||||
|
@JoinColumn( name = "CAR_VENDOR_NR2", referencedColumnName = "VENDOR_NR" )
|
||||||
|
},
|
||||||
|
foreignKey = @ForeignKey( name = "FK_STUDENT_CAR2", value = ConstraintMode.NO_CONSTRAINT )
|
||||||
|
)
|
||||||
|
public Car car2;
|
||||||
|
|
||||||
|
@OneToOne
|
||||||
|
@JoinColumns(
|
||||||
|
value = {
|
||||||
|
@JoinColumn( name = "CAR_NR3", referencedColumnName = "CAR_NR" ),
|
||||||
|
@JoinColumn( name = "CAR_VENDOR_NR3", referencedColumnName = "VENDOR_NR" )
|
||||||
|
},
|
||||||
|
foreignKey = @ForeignKey( name = "FK_STUDENT_CAR3" )
|
||||||
|
)
|
||||||
|
public Car car3;
|
||||||
|
|
||||||
|
@OneToOne
|
||||||
|
@JoinColumns(
|
||||||
|
value = {
|
||||||
|
@JoinColumn( name = "CAR_NR4", referencedColumnName = "CAR_NR" ),
|
||||||
|
@JoinColumn( name = "CAR_VENDOR_NR4", referencedColumnName = "VENDOR_NR" )
|
||||||
|
},
|
||||||
|
foreignKey = @ForeignKey( name = "FK_STUDENT_CAR4", value = ConstraintMode.NO_CONSTRAINT )
|
||||||
|
)
|
||||||
|
public Car car4;
|
||||||
|
|
||||||
|
@ManyToMany
|
||||||
|
@JoinTable(
|
||||||
|
name = "VEHICLE_BUY_INFOS",
|
||||||
|
foreignKey = @ForeignKey( name = "FK_VEHICLE_BUY_INFOS_STUDENT" ),
|
||||||
|
inverseForeignKey = @ForeignKey( name = "FK_VEHICLE_BUY_INFOS_VEHICLE_BUY_INFO" ),
|
||||||
|
joinColumns = @JoinColumn( name = "STUDENT_ID"),
|
||||||
|
inverseJoinColumns = @JoinColumn( name = "VEHICLE_BUY_INFO_ID" )
|
||||||
|
)
|
||||||
|
@MapKeyJoinColumns(
|
||||||
|
value = {
|
||||||
|
@MapKeyJoinColumn( name = "VEHICLE_NR", referencedColumnName = "VEHICLE_NR" ),
|
||||||
|
@MapKeyJoinColumn( name = "VEHICLE_VENDOR_NR", referencedColumnName = "VEHICLE_VENDOR_NR" )
|
||||||
|
},
|
||||||
|
foreignKey = @ForeignKey( name = "FK_VEHICLE_BUY_INFOS_VEHICLE" )
|
||||||
|
)
|
||||||
|
public Map<Vehicle, VehicleBuyInfo> vehicleBuyInfos = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "VehicleBuyInfo")
|
||||||
|
public static class VehicleBuyInfo {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
public long id;
|
||||||
|
public String info;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Vehicle")
|
||||||
|
@Inheritance( strategy = InheritanceType.JOINED )
|
||||||
|
public static class Vehicle {
|
||||||
|
@EmbeddedId
|
||||||
|
public VehicleId id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
public static class VehicleId implements Serializable {
|
||||||
|
@javax.persistence.Column( name = "VEHICLE_VENDOR_NR" )
|
||||||
|
public long vehicleVendorNumber;
|
||||||
|
@javax.persistence.Column( name = "VEHICLE_NR" )
|
||||||
|
public long vehicleNumber;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if ( this == o ) return true;
|
||||||
|
if ( !( o instanceof VehicleId ) ) return false;
|
||||||
|
|
||||||
|
VehicleId vehicleId = (VehicleId) o;
|
||||||
|
|
||||||
|
if ( vehicleVendorNumber != vehicleId.vehicleVendorNumber ) return false;
|
||||||
|
return vehicleNumber == vehicleId.vehicleNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = (int) ( vehicleVendorNumber ^ ( vehicleVendorNumber >>> 32 ) );
|
||||||
|
result = 31 * result + (int) ( vehicleNumber ^ ( vehicleNumber >>> 32 ) );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Car")
|
||||||
|
@SecondaryTable(
|
||||||
|
name = "CAR_DETAILS",
|
||||||
|
pkJoinColumns = {
|
||||||
|
@PrimaryKeyJoinColumn( name = "CAR_NR", referencedColumnName = "CAR_NR" ),
|
||||||
|
@PrimaryKeyJoinColumn( name = "CAR_VENDOR_NR", referencedColumnName = "VENDOR_NR" )
|
||||||
|
},
|
||||||
|
foreignKey = @ForeignKey( name = "FK_CAR_DETAILS_CAR" )
|
||||||
|
)
|
||||||
|
@PrimaryKeyJoinColumns(
|
||||||
|
value = {
|
||||||
|
@PrimaryKeyJoinColumn( name = "CAR_NR", referencedColumnName = "VEHICLE_NR" ),
|
||||||
|
@PrimaryKeyJoinColumn( name = "VENDOR_NR", referencedColumnName = "VEHICLE_VENDOR_NR" )
|
||||||
|
},
|
||||||
|
foreignKey = @ForeignKey( name = "FK_CAR_VEHICLE" )
|
||||||
|
)
|
||||||
|
public static class Car extends Vehicle {
|
||||||
|
|
||||||
|
public String color;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn( name = "OWNER_PERSON_ID", foreignKey = @ForeignKey( name = "FK_CAR_OWNER") )
|
||||||
|
public Person owner;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn( name = "OWNER_PERSON_ID2", foreignKey = @ForeignKey( name = "FK_CAR_OWNER2", value = ConstraintMode.NO_CONSTRAINT ) )
|
||||||
|
public Person owner2;
|
||||||
|
|
||||||
|
@OneToOne
|
||||||
|
@JoinColumn( name = "OWNER_PERSON_ID3", foreignKey = @ForeignKey( name = "FK_CAR_OWNER3") )
|
||||||
|
public Person owner3;
|
||||||
|
|
||||||
|
@OneToOne
|
||||||
|
@JoinColumn( name = "OWNER_PERSON_ID4", foreignKey = @ForeignKey( name = "FK_CAR_OWNER4", value = ConstraintMode.NO_CONSTRAINT ) )
|
||||||
|
public Person owner4;
|
||||||
|
|
||||||
|
@ElementCollection
|
||||||
|
@CollectionTable(
|
||||||
|
name = "OWNER_INFO",
|
||||||
|
joinColumns = {
|
||||||
|
@JoinColumn( name = "CAR_NR" ),
|
||||||
|
@JoinColumn( name = "VENDOR_NR" )
|
||||||
|
},
|
||||||
|
foreignKey = @ForeignKey( name = "FK_OWNER_INFO_CAR" )
|
||||||
|
)
|
||||||
|
@MapKeyJoinColumn( name = "PERSON_ID", foreignKey = @ForeignKey( name = "FK_OWNER_INFO_PERSON" ) )
|
||||||
|
public Map<Person, String> ownerInfo = new HashMap<>();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Truck")
|
||||||
|
@PrimaryKeyJoinColumns(
|
||||||
|
value = {
|
||||||
|
@PrimaryKeyJoinColumn( name = "CAR_NR", referencedColumnName = "VEHICLE_NR" ),
|
||||||
|
@PrimaryKeyJoinColumn( name = "VENDOR_NR", referencedColumnName = "VEHICLE_VENDOR_NR" )
|
||||||
|
},
|
||||||
|
foreignKey = @ForeignKey( name = "FK_TRUCK_VEHICLE", value = ConstraintMode.NO_CONSTRAINT )
|
||||||
|
)
|
||||||
|
public static class Truck extends Vehicle {
|
||||||
|
public boolean fourWheelDrive;
|
||||||
|
}
|
||||||
|
|
||||||
|
@MappedSuperclass
|
||||||
|
public static abstract class AbstractCompany {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
public long id;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn( name = "OWNER_ID" )
|
||||||
|
public Person owner;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn( name = "OWNER_ID2" )
|
||||||
|
public Person owner2;
|
||||||
|
|
||||||
|
@OneToOne
|
||||||
|
@JoinColumn( name = "CC_ID" )
|
||||||
|
public CreditCard creditCard;
|
||||||
|
|
||||||
|
@OneToOne
|
||||||
|
@JoinColumn( name = "CC_ID2" )
|
||||||
|
public CreditCard creditCard2;
|
||||||
|
|
||||||
|
@OneToMany
|
||||||
|
@JoinColumn( name = "CC_ID3" )
|
||||||
|
public List<CreditCard> creditCards1;
|
||||||
|
|
||||||
|
@OneToMany
|
||||||
|
@JoinColumn( name = "CC_ID4" )
|
||||||
|
public List<CreditCard> creditCards2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
public static class CompanyInfo {
|
||||||
|
public String data;
|
||||||
|
|
||||||
|
@OneToMany
|
||||||
|
@JoinColumn( name = "CI_CC_ID", foreignKey = @ForeignKey( name = "FK_CI_CC" ) )
|
||||||
|
public List<CreditCard> cards;
|
||||||
|
|
||||||
|
@OneToMany
|
||||||
|
@JoinColumn( name = "CI_CC_ID2", foreignKey = @ForeignKey( name = "FK_CI_CC2" ) )
|
||||||
|
public List<CreditCard> cards2;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn( name = "CI_CC_ID3", foreignKey = @ForeignKey( name = "FK_CI_CC3" ) )
|
||||||
|
public CreditCard cards3;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn( name = "CI_CC_ID4", foreignKey = @ForeignKey( name = "FK_CI_CC4" ) )
|
||||||
|
public CreditCard cards4;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Company")
|
||||||
|
@AssociationOverrides({
|
||||||
|
@AssociationOverride(
|
||||||
|
name = "owner",
|
||||||
|
joinColumns = @JoinColumn( name = "OWNER_PERSON_ID" ),
|
||||||
|
foreignKey = @ForeignKey( name = "FK_COMPANY_OWNER" )
|
||||||
|
),
|
||||||
|
@AssociationOverride(
|
||||||
|
name = "owner2",
|
||||||
|
joinColumns = @JoinColumn( name = "OWNER_PERSON_ID2" ),
|
||||||
|
foreignKey = @ForeignKey( name = "FK_COMPANY_OWNER2", value = ConstraintMode.NO_CONSTRAINT )
|
||||||
|
),
|
||||||
|
@AssociationOverride(
|
||||||
|
name = "creditCard",
|
||||||
|
joinColumns = @JoinColumn( name = "CREDIT_CARD_ID" ),
|
||||||
|
foreignKey = @ForeignKey( name = "FK_COMPANY_CREDIT_CARD" )
|
||||||
|
),
|
||||||
|
@AssociationOverride(
|
||||||
|
name = "creditCard2",
|
||||||
|
joinColumns = @JoinColumn( name = "CREDIT_CARD_ID2" ),
|
||||||
|
foreignKey = @ForeignKey( name = "FK_COMPANY_CREDIT_CARD2", value = ConstraintMode.NO_CONSTRAINT )
|
||||||
|
),
|
||||||
|
@AssociationOverride(
|
||||||
|
name = "creditCards1",
|
||||||
|
joinColumns = @JoinColumn( name = "CREDIT_CARD_ID3" ),
|
||||||
|
foreignKey = @ForeignKey( name = "FK_COMPANY_CREDIT_CARD3" )
|
||||||
|
),
|
||||||
|
@AssociationOverride(
|
||||||
|
name = "creditCards2",
|
||||||
|
joinColumns = @JoinColumn( name = "CREDIT_CARD_ID4" ),
|
||||||
|
foreignKey = @ForeignKey( name = "FK_COMPANY_CREDIT_CARD4", value = ConstraintMode.NO_CONSTRAINT )
|
||||||
|
)
|
||||||
|
|
||||||
|
})
|
||||||
|
public static class Company extends AbstractCompany {
|
||||||
|
@Embedded
|
||||||
|
@AssociationOverrides({
|
||||||
|
@AssociationOverride(
|
||||||
|
name = "cards",
|
||||||
|
joinColumns = @JoinColumn( name = "AO_CI_CC_ID" ),
|
||||||
|
foreignKey = @ForeignKey( name = "FK_COMPANY_CARD" )
|
||||||
|
),
|
||||||
|
@AssociationOverride(
|
||||||
|
name = "cards2",
|
||||||
|
joinColumns = @JoinColumn( name = "AO_CI_CC_ID2" ),
|
||||||
|
foreignKey = @ForeignKey( name = "FK_COMPANY_CARD2", value = ConstraintMode.NO_CONSTRAINT )
|
||||||
|
),
|
||||||
|
@AssociationOverride(
|
||||||
|
name = "cards3",
|
||||||
|
joinColumns = @JoinColumn( name = "AO_CI_CC_ID3" ),
|
||||||
|
foreignKey = @ForeignKey( name = "FK_COMPANY_CARD3" )
|
||||||
|
),
|
||||||
|
@AssociationOverride(
|
||||||
|
name = "cards4",
|
||||||
|
joinColumns = @JoinColumn( name = "AO_CI_CC_ID4" ),
|
||||||
|
foreignKey = @ForeignKey( name = "FK_COMPANY_CARD4", value = ConstraintMode.NO_CONSTRAINT )
|
||||||
|
)
|
||||||
|
})
|
||||||
|
public CompanyInfo info;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue