use of org.hibernate.annotations.ForeignKey in project hibernate-orm by hibernate.
the class AnnotationBinder method bindClass.
/**
* Bind a class having JSR175 annotations. Subclasses <b>have to</b> be bound after its parent class.
*
* @param clazzToProcess entity to bind as {@code XClass} instance
* @param inheritanceStatePerClass Meta data about the inheritance relationships for all mapped classes
*
* @throws MappingException in case there is a configuration error
*/
public static void bindClass(XClass clazzToProcess, Map<XClass, InheritanceState> inheritanceStatePerClass, MetadataBuildingContext context) throws MappingException {
// @Entity and @MappedSuperclass on the same class leads to a NPE down the road
if (clazzToProcess.isAnnotationPresent(Entity.class) && clazzToProcess.isAnnotationPresent(MappedSuperclass.class)) {
throw new AnnotationException("An entity cannot be annotated with both @Entity and @MappedSuperclass: " + clazzToProcess.getName());
}
// TODO: be more strict with secondarytable allowance (not for ids, not for secondary table join columns etc)
InheritanceState inheritanceState = inheritanceStatePerClass.get(clazzToProcess);
AnnotatedClassType classType = context.getMetadataCollector().getClassType(clazzToProcess);
// Queries declared in MappedSuperclass should be usable in Subclasses
if (AnnotatedClassType.EMBEDDABLE_SUPERCLASS.equals(classType)) {
bindQueries(clazzToProcess, context);
bindTypeDefs(clazzToProcess, context);
bindFilterDefs(clazzToProcess, context);
}
if (!isEntityClassType(clazzToProcess, classType)) {
return;
}
if (LOG.isDebugEnabled()) {
LOG.debugf("Binding entity from annotated class: %s", clazzToProcess.getName());
}
PersistentClass superEntity = getSuperEntity(clazzToProcess, inheritanceStatePerClass, context, inheritanceState);
PersistentClass persistentClass = makePersistentClass(inheritanceState, superEntity, context);
Entity entityAnn = clazzToProcess.getAnnotation(Entity.class);
org.hibernate.annotations.Entity hibEntityAnn = clazzToProcess.getAnnotation(org.hibernate.annotations.Entity.class);
EntityBinder entityBinder = new EntityBinder(entityAnn, hibEntityAnn, clazzToProcess, persistentClass, context);
entityBinder.setInheritanceState(inheritanceState);
bindQueries(clazzToProcess, context);
bindFilterDefs(clazzToProcess, context);
bindTypeDefs(clazzToProcess, context);
bindFetchProfiles(clazzToProcess, context);
BinderHelper.bindAnyMetaDefs(clazzToProcess, context);
String schema = "";
// might be no @Table annotation on the annotated class
String table = "";
String catalog = "";
List<UniqueConstraintHolder> uniqueConstraints = new ArrayList<>();
javax.persistence.Table tabAnn = null;
if (clazzToProcess.isAnnotationPresent(javax.persistence.Table.class)) {
tabAnn = clazzToProcess.getAnnotation(javax.persistence.Table.class);
table = tabAnn.name();
schema = tabAnn.schema();
catalog = tabAnn.catalog();
uniqueConstraints = TableBinder.buildUniqueConstraintHolders(tabAnn.uniqueConstraints());
}
Ejb3JoinColumn[] inheritanceJoinedColumns = makeInheritanceJoinColumns(clazzToProcess, context, inheritanceState, superEntity);
final Ejb3DiscriminatorColumn discriminatorColumn;
if (InheritanceType.SINGLE_TABLE.equals(inheritanceState.getType())) {
discriminatorColumn = processSingleTableDiscriminatorProperties(clazzToProcess, context, inheritanceState, entityBinder);
} else if (InheritanceType.JOINED.equals(inheritanceState.getType())) {
discriminatorColumn = processJoinedDiscriminatorProperties(clazzToProcess, context, inheritanceState, entityBinder);
} else {
discriminatorColumn = null;
}
entityBinder.setProxy(clazzToProcess.getAnnotation(Proxy.class));
entityBinder.setBatchSize(clazzToProcess.getAnnotation(BatchSize.class));
entityBinder.setWhere(clazzToProcess.getAnnotation(Where.class));
applyCacheSettings(entityBinder, clazzToProcess, context);
bindFilters(clazzToProcess, entityBinder, context);
entityBinder.bindEntity();
if (inheritanceState.hasTable()) {
Check checkAnn = clazzToProcess.getAnnotation(Check.class);
String constraints = checkAnn == null ? null : checkAnn.constraints();
EntityTableXref denormalizedTableXref = inheritanceState.hasDenormalizedTable() ? context.getMetadataCollector().getEntityTableXref(superEntity.getEntityName()) : null;
entityBinder.bindTable(schema, catalog, table, uniqueConstraints, constraints, denormalizedTableXref);
} else {
if (clazzToProcess.isAnnotationPresent(Table.class)) {
LOG.invalidTableAnnotation(clazzToProcess.getName());
}
if (inheritanceState.getType() == InheritanceType.SINGLE_TABLE) {
// we at least need to properly set up the EntityTableXref
entityBinder.bindTableForDiscriminatedSubclass(context.getMetadataCollector().getEntityTableXref(superEntity.getEntityName()));
}
}
PropertyHolder propertyHolder = PropertyHolderBuilder.buildPropertyHolder(clazzToProcess, persistentClass, entityBinder, context, inheritanceStatePerClass);
javax.persistence.SecondaryTable secTabAnn = clazzToProcess.getAnnotation(javax.persistence.SecondaryTable.class);
javax.persistence.SecondaryTables secTabsAnn = clazzToProcess.getAnnotation(javax.persistence.SecondaryTables.class);
entityBinder.firstLevelSecondaryTablesBinding(secTabAnn, secTabsAnn);
OnDelete onDeleteAnn = clazzToProcess.getAnnotation(OnDelete.class);
boolean onDeleteAppropriate = false;
// todo : sucks that this is separate from RootClass distinction
final boolean isInheritanceRoot = !inheritanceState.hasParents();
final boolean hasSubclasses = inheritanceState.hasSiblings();
if (InheritanceType.JOINED.equals(inheritanceState.getType())) {
if (inheritanceState.hasParents()) {
onDeleteAppropriate = true;
final JoinedSubclass jsc = (JoinedSubclass) persistentClass;
SimpleValue key = new DependantValue(context, jsc.getTable(), jsc.getIdentifier());
jsc.setKey(key);
ForeignKey fk = clazzToProcess.getAnnotation(ForeignKey.class);
if (fk != null && !BinderHelper.isEmptyAnnotationValue(fk.name())) {
key.setForeignKeyName(fk.name());
} else {
final PrimaryKeyJoinColumn pkJoinColumn = clazzToProcess.getAnnotation(PrimaryKeyJoinColumn.class);
final PrimaryKeyJoinColumns pkJoinColumns = clazzToProcess.getAnnotation(PrimaryKeyJoinColumns.class);
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());
}
}
if (onDeleteAnn != null) {
key.setCascadeDeleteEnabled(OnDeleteAction.CASCADE.equals(onDeleteAnn.action()));
} else {
key.setCascadeDeleteEnabled(false);
}
// we are never in a second pass at that stage, so queue it
context.getMetadataCollector().addSecondPass(new JoinedSubclassFkSecondPass(jsc, inheritanceJoinedColumns, key, context));
context.getMetadataCollector().addSecondPass(new CreateKeySecondPass(jsc));
}
if (isInheritanceRoot) {
// (it is perfectly valid for joined subclasses to not have discriminators).
if (discriminatorColumn != null) {
// we have a discriminator column
if (hasSubclasses || !discriminatorColumn.isImplicit()) {
bindDiscriminatorColumnToRootPersistentClass((RootClass) persistentClass, discriminatorColumn, entityBinder.getSecondaryTables(), propertyHolder, context);
// bind it again since the type might have changed
entityBinder.bindDiscriminatorValue();
}
}
}
} else if (InheritanceType.SINGLE_TABLE.equals(inheritanceState.getType())) {
if (isInheritanceRoot) {
if (hasSubclasses || !discriminatorColumn.isImplicit()) {
bindDiscriminatorColumnToRootPersistentClass((RootClass) persistentClass, discriminatorColumn, entityBinder.getSecondaryTables(), propertyHolder, context);
// bind it again since the type might have changed
entityBinder.bindDiscriminatorValue();
}
}
}
if (onDeleteAnn != null && !onDeleteAppropriate) {
LOG.invalidOnDeleteAnnotation(propertyHolder.getEntityName());
}
// try to find class level generators
HashMap<String, IdentifierGeneratorDefinition> classGenerators = buildGenerators(clazzToProcess, context);
// check properties
final InheritanceState.ElementsToProcess elementsToProcess = inheritanceState.getElementsToProcess();
inheritanceState.postProcess(persistentClass, entityBinder);
final boolean subclassAndSingleTableStrategy = inheritanceState.getType() == InheritanceType.SINGLE_TABLE && inheritanceState.hasParents();
Set<String> idPropertiesIfIdClass = new HashSet<>();
boolean isIdClass = mapAsIdClass(inheritanceStatePerClass, inheritanceState, persistentClass, entityBinder, propertyHolder, elementsToProcess, idPropertiesIfIdClass, context);
if (!isIdClass) {
entityBinder.setWrapIdsInEmbeddedComponents(elementsToProcess.getIdPropertyCount() > 1);
}
processIdPropertiesIfNotAlready(inheritanceStatePerClass, context, persistentClass, entityBinder, propertyHolder, classGenerators, elementsToProcess, subclassAndSingleTableStrategy, idPropertiesIfIdClass);
if (!inheritanceState.hasParents()) {
final RootClass rootClass = (RootClass) persistentClass;
context.getMetadataCollector().addSecondPass(new CreateKeySecondPass(rootClass));
} else {
superEntity.addSubclass((Subclass) persistentClass);
}
context.getMetadataCollector().addEntityBinding(persistentClass);
// Process secondary tables and complementary definitions (ie o.h.a.Table)
context.getMetadataCollector().addSecondPass(new SecondaryTableSecondPass(entityBinder, propertyHolder, clazzToProcess));
// add process complementary Table definition (index & all)
entityBinder.processComplementaryTableDefinitions(clazzToProcess.getAnnotation(org.hibernate.annotations.Table.class));
entityBinder.processComplementaryTableDefinitions(clazzToProcess.getAnnotation(org.hibernate.annotations.Tables.class));
entityBinder.processComplementaryTableDefinitions(tabAnn);
}
use of org.hibernate.annotations.ForeignKey in project hibernate-orm by hibernate.
the class CollectionBinder method buildCollectionKey.
private static SimpleValue buildCollectionKey(Collection collValue, Ejb3JoinColumn[] joinColumns, boolean cascadeDeleteEnabled, XProperty property, PropertyHolder propertyHolder, MetadataBuildingContext buildingContext) {
// binding key reference using column
KeyValue keyVal;
// has to do that here because the referencedProperty creation happens in a FKSecondPass for Many to one yuk!
if (joinColumns.length > 0 && StringHelper.isNotEmpty(joinColumns[0].getMappedBy())) {
String entityName = joinColumns[0].getManyToManyOwnerSideEntityName() != null ? "inverse__" + joinColumns[0].getManyToManyOwnerSideEntityName() : joinColumns[0].getPropertyHolder().getEntityName();
String propRef = buildingContext.getMetadataCollector().getPropertyReferencedAssociation(entityName, joinColumns[0].getMappedBy());
if (propRef != null) {
collValue.setReferencedPropertyName(propRef);
buildingContext.getMetadataCollector().addPropertyReference(collValue.getOwnerEntityName(), propRef);
}
}
String propRef = collValue.getReferencedPropertyName();
if (propRef == null) {
keyVal = collValue.getOwner().getIdentifier();
} else {
keyVal = (KeyValue) collValue.getOwner().getReferencedProperty(propRef).getValue();
}
DependantValue key = new DependantValue(buildingContext, collValue.getCollectionTable(), keyVal);
key.setTypeName(null);
Ejb3Column.checkPropertyConsistency(joinColumns, collValue.getOwnerEntityName());
key.setNullable(joinColumns.length == 0 || joinColumns[0].isNullable());
key.setUpdateable(joinColumns.length == 0 || joinColumns[0].isUpdatable());
key.setCascadeDeleteEnabled(cascadeDeleteEnabled);
collValue.setKey(key);
if (property != null) {
final ForeignKey fk = property.getAnnotation(ForeignKey.class);
if (fk != null && !BinderHelper.isEmptyAnnotationValue(fk.name())) {
key.setForeignKeyName(fk.name());
} else {
final CollectionTable collectionTableAnn = property.getAnnotation(CollectionTable.class);
if (collectionTableAnn != null) {
if (collectionTableAnn.foreignKey().value() == ConstraintMode.NO_CONSTRAINT) {
key.setForeignKeyName("none");
} else {
key.setForeignKeyName(StringHelper.nullIfEmpty(collectionTableAnn.foreignKey().name()));
key.setForeignKeyDefinition(StringHelper.nullIfEmpty(collectionTableAnn.foreignKey().foreignKeyDefinition()));
if (key.getForeignKeyName() == null && key.getForeignKeyDefinition() == null && collectionTableAnn.joinColumns().length == 1) {
JoinColumn joinColumn = collectionTableAnn.joinColumns()[0];
key.setForeignKeyName(StringHelper.nullIfEmpty(joinColumn.foreignKey().name()));
key.setForeignKeyDefinition(StringHelper.nullIfEmpty(joinColumn.foreignKey().foreignKeyDefinition()));
}
}
} else {
final JoinTable joinTableAnn = property.getAnnotation(JoinTable.class);
if (joinTableAnn != null) {
String foreignKeyName = joinTableAnn.foreignKey().name();
String foreignKeyDefinition = joinTableAnn.foreignKey().foreignKeyDefinition();
ConstraintMode foreignKeyValue = joinTableAnn.foreignKey().value();
if (joinTableAnn.joinColumns().length != 0) {
final JoinColumn joinColumnAnn = joinTableAnn.joinColumns()[0];
if ("".equals(foreignKeyName)) {
foreignKeyName = joinColumnAnn.foreignKey().name();
foreignKeyDefinition = joinColumnAnn.foreignKey().foreignKeyDefinition();
}
if (foreignKeyValue != ConstraintMode.NO_CONSTRAINT) {
foreignKeyValue = joinColumnAnn.foreignKey().value();
}
}
if (foreignKeyValue == ConstraintMode.NO_CONSTRAINT) {
key.setForeignKeyName("none");
} else {
key.setForeignKeyName(StringHelper.nullIfEmpty(foreignKeyName));
key.setForeignKeyDefinition(StringHelper.nullIfEmpty(foreignKeyDefinition));
}
} else {
final javax.persistence.ForeignKey fkOverride = propertyHolder.getOverriddenForeignKey(StringHelper.qualify(propertyHolder.getPath(), property.getName()));
if (fkOverride != null && fkOverride.value() == ConstraintMode.NO_CONSTRAINT) {
key.setForeignKeyName("none");
} else if (fkOverride != null) {
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()));
}
}
}
}
}
}
}
return key;
}
use of org.hibernate.annotations.ForeignKey in project hibernate-orm by hibernate.
the class CollectionBinder method bindManyToManySecondPass.
private void bindManyToManySecondPass(Collection collValue, Map persistentClasses, Ejb3JoinColumn[] joinColumns, Ejb3JoinColumn[] inverseJoinColumns, Ejb3Column[] elementColumns, boolean isEmbedded, XClass collType, boolean ignoreNotFound, boolean unique, boolean cascadeDeleteEnabled, TableBinder associationTableBinder, XProperty property, PropertyHolder parentPropertyHolder, MetadataBuildingContext buildingContext) throws MappingException {
if (property == null) {
throw new IllegalArgumentException("null was passed for argument property");
}
final PersistentClass collectionEntity = (PersistentClass) persistentClasses.get(collType.getName());
final String hqlOrderBy = extractHqlOrderBy(jpaOrderBy);
boolean isCollectionOfEntities = collectionEntity != null;
ManyToAny anyAnn = property.getAnnotation(ManyToAny.class);
if (LOG.isDebugEnabled()) {
String path = collValue.getOwnerEntityName() + "." + joinColumns[0].getPropertyName();
if (isCollectionOfEntities && unique) {
LOG.debugf("Binding a OneToMany: %s through an association table", path);
} else if (isCollectionOfEntities) {
LOG.debugf("Binding as ManyToMany: %s", path);
} else if (anyAnn != null) {
LOG.debugf("Binding a ManyToAny: %s", path);
} else {
LOG.debugf("Binding a collection of element: %s", path);
}
}
// check for user error
if (!isCollectionOfEntities) {
if (property.isAnnotationPresent(ManyToMany.class) || property.isAnnotationPresent(OneToMany.class)) {
String path = collValue.getOwnerEntityName() + "." + joinColumns[0].getPropertyName();
throw new AnnotationException("Use of @OneToMany or @ManyToMany targeting an unmapped class: " + path + "[" + collType + "]");
} else if (anyAnn != null) {
if (parentPropertyHolder.getJoinTable(property) == null) {
String path = collValue.getOwnerEntityName() + "." + joinColumns[0].getPropertyName();
throw new AnnotationException("@JoinTable is mandatory when @ManyToAny is used: " + path);
}
} else {
JoinTable joinTableAnn = parentPropertyHolder.getJoinTable(property);
if (joinTableAnn != null && joinTableAnn.inverseJoinColumns().length > 0) {
String path = collValue.getOwnerEntityName() + "." + joinColumns[0].getPropertyName();
throw new AnnotationException("Use of @JoinTable.inverseJoinColumns targeting an unmapped class: " + path + "[" + collType + "]");
}
}
}
boolean mappedBy = !BinderHelper.isEmptyAnnotationValue(joinColumns[0].getMappedBy());
if (mappedBy) {
if (!isCollectionOfEntities) {
throw new AnnotationException("Collection of elements must not have mappedBy or association reference an unmapped entity: " + collValue.getOwnerEntityName() + "." + joinColumns[0].getPropertyName());
}
Property otherSideProperty;
try {
otherSideProperty = collectionEntity.getRecursiveProperty(joinColumns[0].getMappedBy());
} catch (MappingException e) {
throw new AnnotationException("mappedBy reference an unknown target entity property: " + collType + "." + joinColumns[0].getMappedBy() + " in " + collValue.getOwnerEntityName() + "." + joinColumns[0].getPropertyName());
}
Table table;
if (otherSideProperty.getValue() instanceof Collection) {
// this is a collection on the other side
table = ((Collection) otherSideProperty.getValue()).getCollectionTable();
} else {
// This is a ToOne with a @JoinTable or a regular property
table = otherSideProperty.getValue().getTable();
}
collValue.setCollectionTable(table);
String entityName = collectionEntity.getEntityName();
for (Ejb3JoinColumn column : joinColumns) {
// column.setDefaultColumnHeader( joinColumns[0].getMappedBy() ); //seems not to be used, make sense
column.setManyToManyOwnerSideEntityName(entityName);
}
} else {
// FIXME NamingStrategy
for (Ejb3JoinColumn column : joinColumns) {
String mappedByProperty = buildingContext.getMetadataCollector().getFromMappedBy(collValue.getOwnerEntityName(), column.getPropertyName());
Table ownerTable = collValue.getOwner().getTable();
column.setMappedBy(collValue.getOwner().getEntityName(), collValue.getOwner().getJpaEntityName(), buildingContext.getMetadataCollector().getLogicalTableName(ownerTable), mappedByProperty);
// String header = ( mappedByProperty == null ) ? mappings.getLogicalTableName( ownerTable ) : mappedByProperty;
// column.setDefaultColumnHeader( header );
}
if (StringHelper.isEmpty(associationTableBinder.getName())) {
// default value
associationTableBinder.setDefaultName(collValue.getOwner().getClassName(), collValue.getOwner().getEntityName(), collValue.getOwner().getJpaEntityName(), buildingContext.getMetadataCollector().getLogicalTableName(collValue.getOwner().getTable()), collectionEntity != null ? collectionEntity.getClassName() : null, collectionEntity != null ? collectionEntity.getEntityName() : null, collectionEntity != null ? collectionEntity.getJpaEntityName() : null, collectionEntity != null ? buildingContext.getMetadataCollector().getLogicalTableName(collectionEntity.getTable()) : null, joinColumns[0].getPropertyName());
}
associationTableBinder.setJPA2ElementCollection(!isCollectionOfEntities && property.isAnnotationPresent(ElementCollection.class));
collValue.setCollectionTable(associationTableBinder.bind());
}
bindFilters(isCollectionOfEntities);
bindCollectionSecondPass(collValue, collectionEntity, joinColumns, cascadeDeleteEnabled, property, propertyHolder, buildingContext);
ManyToOne element = null;
if (isCollectionOfEntities) {
element = new ManyToOne(buildingContext, collValue.getCollectionTable());
collValue.setElement(element);
element.setReferencedEntityName(collType.getName());
// element.setFetchMode( fetchMode );
// element.setLazy( fetchMode != FetchMode.JOIN );
// make the second join non lazy
element.setFetchMode(FetchMode.JOIN);
element.setLazy(false);
element.setIgnoreNotFound(ignoreNotFound);
// as per 11.1.38 of JPA 2.0 spec, default to primary key if no column is specified by @OrderBy.
if (hqlOrderBy != null) {
collValue.setManyToManyOrdering(buildOrderByClauseFromHql(hqlOrderBy, collectionEntity, collValue.getRole()));
}
final ForeignKey fk = property.getAnnotation(ForeignKey.class);
if (fk != null && !BinderHelper.isEmptyAnnotationValue(fk.name())) {
element.setForeignKeyName(fk.name());
} else {
final JoinTable joinTableAnn = property.getAnnotation(JoinTable.class);
if (joinTableAnn != null) {
String foreignKeyName = joinTableAnn.inverseForeignKey().name();
String foreignKeyDefinition = joinTableAnn.inverseForeignKey().foreignKeyDefinition();
ConstraintMode foreignKeyValue = joinTableAnn.inverseForeignKey().value();
if (joinTableAnn.inverseJoinColumns().length != 0) {
final JoinColumn joinColumnAnn = joinTableAnn.inverseJoinColumns()[0];
if ("".equals(foreignKeyName)) {
foreignKeyName = joinColumnAnn.foreignKey().name();
foreignKeyDefinition = joinColumnAnn.foreignKey().foreignKeyDefinition();
}
if (foreignKeyValue != ConstraintMode.NO_CONSTRAINT) {
foreignKeyValue = joinColumnAnn.foreignKey().value();
}
}
if (joinTableAnn.inverseForeignKey().value() == ConstraintMode.NO_CONSTRAINT) {
element.setForeignKeyName("none");
} else {
element.setForeignKeyName(StringHelper.nullIfEmpty(foreignKeyName));
element.setForeignKeyDefinition(StringHelper.nullIfEmpty(foreignKeyDefinition));
}
}
}
} else if (anyAnn != null) {
// @ManyToAny
// Make sure that collTyp is never used during the @ManyToAny branch: it will be set to void.class
PropertyData inferredData = new PropertyInferredData(null, property, "unsupported", buildingContext.getBootstrapContext().getReflectionManager());
// override the table
for (Ejb3Column column : inverseJoinColumns) {
column.setTable(collValue.getCollectionTable());
}
Any any = BinderHelper.buildAnyValue(anyAnn.metaDef(), inverseJoinColumns, anyAnn.metaColumn(), inferredData, cascadeDeleteEnabled, Nullability.NO_CONSTRAINT, propertyHolder, new EntityBinder(), true, buildingContext);
collValue.setElement(any);
} else {
XClass elementClass;
AnnotatedClassType classType;
CollectionPropertyHolder holder;
if (BinderHelper.PRIMITIVE_NAMES.contains(collType.getName())) {
classType = AnnotatedClassType.NONE;
elementClass = null;
holder = PropertyHolderBuilder.buildPropertyHolder(collValue, collValue.getRole(), null, property, parentPropertyHolder, buildingContext);
} else {
elementClass = collType;
classType = buildingContext.getMetadataCollector().getClassType(elementClass);
holder = PropertyHolderBuilder.buildPropertyHolder(collValue, collValue.getRole(), elementClass, property, parentPropertyHolder, buildingContext);
// 'parentPropertyHolder' is the PropertyHolder for the owner of the collection
// 'holder' is the CollectionPropertyHolder.
// 'property' is the collection XProperty
parentPropertyHolder.startingProperty(property);
// force in case of attribute override
boolean attributeOverride = property.isAnnotationPresent(AttributeOverride.class) || property.isAnnotationPresent(AttributeOverrides.class);
// todo : force in the case of Convert annotation(s) with embedded paths (beyond key/value prefixes)?
if (isEmbedded || attributeOverride) {
classType = AnnotatedClassType.EMBEDDABLE;
}
}
if (AnnotatedClassType.EMBEDDABLE.equals(classType)) {
holder.prepare(property);
EntityBinder entityBinder = new EntityBinder();
PersistentClass owner = collValue.getOwner();
boolean isPropertyAnnotated;
// String accessType = access != null ? access.value() : null;
if (owner.getIdentifierProperty() != null) {
isPropertyAnnotated = owner.getIdentifierProperty().getPropertyAccessorName().equals("property");
} else if (owner.getIdentifierMapper() != null && owner.getIdentifierMapper().getPropertySpan() > 0) {
Property prop = (Property) owner.getIdentifierMapper().getPropertyIterator().next();
isPropertyAnnotated = prop.getPropertyAccessorName().equals("property");
} else {
throw new AssertionFailure("Unable to guess collection property accessor name");
}
PropertyData inferredData;
if (isMap()) {
// "value" is the JPA 2 prefix for map values (used to be "element")
if (isHibernateExtensionMapping()) {
inferredData = new PropertyPreloadedData(AccessType.PROPERTY, "element", elementClass);
} else {
inferredData = new PropertyPreloadedData(AccessType.PROPERTY, "value", elementClass);
}
} else {
if (isHibernateExtensionMapping()) {
inferredData = new PropertyPreloadedData(AccessType.PROPERTY, "element", elementClass);
} else {
// "collection&&element" is not a valid property name => placeholder
inferredData = new PropertyPreloadedData(AccessType.PROPERTY, "collection&&element", elementClass);
}
}
// TODO be smart with isNullable
boolean isNullable = true;
Component component = AnnotationBinder.fillComponent(holder, inferredData, isPropertyAnnotated ? AccessType.PROPERTY : AccessType.FIELD, isNullable, entityBinder, false, false, true, buildingContext, inheritanceStatePerClass);
collValue.setElement(component);
if (StringHelper.isNotEmpty(hqlOrderBy)) {
String orderBy = adjustUserSuppliedValueCollectionOrderingFragment(hqlOrderBy);
if (orderBy != null) {
collValue.setOrderBy(orderBy);
}
}
} else {
holder.prepare(property);
SimpleValueBinder elementBinder = new SimpleValueBinder();
elementBinder.setBuildingContext(buildingContext);
elementBinder.setReturnedClassName(collType.getName());
if (elementColumns == null || elementColumns.length == 0) {
elementColumns = new Ejb3Column[1];
Ejb3Column column = new Ejb3Column();
column.setImplicit(false);
// not following the spec but more clean
column.setNullable(true);
column.setLength(Ejb3Column.DEFAULT_COLUMN_LENGTH);
column.setLogicalColumnName(Collection.DEFAULT_ELEMENT_COLUMN_NAME);
// TODO create an EMPTY_JOINS collection
column.setJoins(new HashMap<>());
column.setBuildingContext(buildingContext);
column.bind();
elementColumns[0] = column;
}
// override the table
for (Ejb3Column column : elementColumns) {
column.setTable(collValue.getCollectionTable());
}
elementBinder.setColumns(elementColumns);
elementBinder.setType(property, elementClass, collValue.getOwnerEntityName(), holder.resolveElementAttributeConverterDescriptor(property, elementClass));
elementBinder.setPersistentClassName(propertyHolder.getEntityName());
elementBinder.setAccessType(accessType);
collValue.setElement(elementBinder.make());
String orderBy = adjustUserSuppliedValueCollectionOrderingFragment(hqlOrderBy);
if (orderBy != null) {
collValue.setOrderBy(orderBy);
}
}
}
checkFilterConditions(collValue);
// FIXME: do optional = false
if (isCollectionOfEntities) {
bindManytoManyInverseFk(collectionEntity, inverseJoinColumns, element, unique, buildingContext);
}
}
use of org.hibernate.annotations.ForeignKey in project hibernate-orm by hibernate.
the class OneToOneSecondPass method doSecondPass.
// TODO refactor this code, there is a lot of duplication in this method
public void doSecondPass(Map persistentClasses) throws MappingException {
org.hibernate.mapping.OneToOne value = new org.hibernate.mapping.OneToOne(buildingContext, propertyHolder.getTable(), propertyHolder.getPersistentClass());
final String propertyName = inferredData.getPropertyName();
value.setPropertyName(propertyName);
String referencedEntityName = ToOneBinder.getReferenceEntityName(inferredData, targetEntity, buildingContext);
value.setReferencedEntityName(referencedEntityName);
AnnotationBinder.defineFetchingStrategy(value, inferredData.getProperty());
// value.setFetchMode( fetchMode );
value.setCascadeDeleteEnabled(cascadeOnDelete);
if (!optional) {
value.setConstrained(true);
}
if (value.isReferenceToPrimaryKey()) {
value.setForeignKeyType(ForeignKeyDirection.TO_PARENT);
} else {
value.setForeignKeyType(value.isConstrained() ? ForeignKeyDirection.FROM_PARENT : ForeignKeyDirection.TO_PARENT);
}
PropertyBinder binder = new PropertyBinder();
binder.setName(propertyName);
binder.setValue(value);
binder.setCascade(cascadeStrategy);
binder.setAccessType(inferredData.getDefaultAccess());
final LazyGroup lazyGroupAnnotation = inferredData.getProperty().getAnnotation(LazyGroup.class);
if (lazyGroupAnnotation != null) {
binder.setLazyGroup(lazyGroupAnnotation.value());
}
Property prop = binder.makeProperty();
prop.setOptional(optional);
if (BinderHelper.isEmptyAnnotationValue(mappedBy)) {
/*
* we need to check if the columns are in the right order
* if not, then we need to create a many to one and formula
* but actually, since entities linked by a one to one need
* to share the same composite id class, this cannot happen in hibernate
*/
boolean rightOrder = true;
if (rightOrder) {
String path = StringHelper.qualify(propertyHolder.getPath(), propertyName);
final ToOneFkSecondPass secondPass = new ToOneFkSecondPass(value, joinColumns, // cannot have nullabe and unique on certain DBs
!optional, propertyHolder.getEntityOwnerClassName(), path, buildingContext);
secondPass.doSecondPass(persistentClasses);
// no column associated since its a one to one
propertyHolder.addProperty(prop, inferredData.getDeclaringClass());
} else {
// this is a many to one with Formula
}
} else {
PersistentClass otherSide = (PersistentClass) persistentClasses.get(value.getReferencedEntityName());
Property otherSideProperty;
try {
if (otherSide == null) {
throw new MappingException("Unable to find entity: " + value.getReferencedEntityName());
}
otherSideProperty = BinderHelper.findPropertyByName(otherSide, mappedBy);
} catch (MappingException e) {
throw new AnnotationException("Unknown mappedBy in: " + StringHelper.qualify(ownerEntity, ownerProperty) + ", referenced property unknown: " + StringHelper.qualify(value.getReferencedEntityName(), mappedBy));
}
if (otherSideProperty == null) {
throw new AnnotationException("Unknown mappedBy in: " + StringHelper.qualify(ownerEntity, ownerProperty) + ", referenced property unknown: " + StringHelper.qualify(value.getReferencedEntityName(), mappedBy));
}
if (otherSideProperty.getValue() instanceof OneToOne) {
propertyHolder.addProperty(prop, inferredData.getDeclaringClass());
} else if (otherSideProperty.getValue() instanceof ManyToOne) {
Iterator it = otherSide.getJoinIterator();
Join otherSideJoin = null;
while (it.hasNext()) {
Join otherSideJoinValue = (Join) it.next();
if (otherSideJoinValue.containsProperty(otherSideProperty)) {
otherSideJoin = otherSideJoinValue;
break;
}
}
if (otherSideJoin != null) {
// @OneToOne @JoinTable
Join mappedByJoin = buildJoinFromMappedBySide((PersistentClass) persistentClasses.get(ownerEntity), otherSideProperty, otherSideJoin);
ManyToOne manyToOne = new ManyToOne(buildingContext, mappedByJoin.getTable());
// FIXME use ignore not found here
manyToOne.setIgnoreNotFound(ignoreNotFound);
manyToOne.setCascadeDeleteEnabled(value.isCascadeDeleteEnabled());
manyToOne.setFetchMode(value.getFetchMode());
manyToOne.setLazy(value.isLazy());
manyToOne.setReferencedEntityName(value.getReferencedEntityName());
manyToOne.setUnwrapProxy(value.isUnwrapProxy());
prop.setValue(manyToOne);
Iterator otherSideJoinKeyColumns = otherSideJoin.getKey().getColumnIterator();
while (otherSideJoinKeyColumns.hasNext()) {
Column column = (Column) otherSideJoinKeyColumns.next();
Column copy = new Column();
copy.setLength(column.getLength());
copy.setScale(column.getScale());
copy.setValue(manyToOne);
copy.setName(column.getQuotedName());
copy.setNullable(column.isNullable());
copy.setPrecision(column.getPrecision());
copy.setUnique(column.isUnique());
copy.setSqlType(column.getSqlType());
copy.setCheckConstraint(column.getCheckConstraint());
copy.setComment(column.getComment());
copy.setDefaultValue(column.getDefaultValue());
manyToOne.addColumn(copy);
}
mappedByJoin.addProperty(prop);
} else {
propertyHolder.addProperty(prop, inferredData.getDeclaringClass());
}
value.setReferencedPropertyName(mappedBy);
// HHH-6813
// Foo: @Id long id, @OneToOne(mappedBy="foo") Bar bar
// Bar: @Id @OneToOne Foo foo
boolean referencesDerivedId = false;
try {
referencesDerivedId = otherSide.getIdentifier() instanceof Component && ((Component) otherSide.getIdentifier()).getProperty(mappedBy) != null;
} catch (MappingException e) {
// ignore
}
boolean referenceToPrimaryKey = referencesDerivedId || mappedBy == null;
value.setReferenceToPrimaryKey(referenceToPrimaryKey);
// loop of attempts to resolve identifiers.
if (referencesDerivedId) {
((ManyToOne) otherSideProperty.getValue()).setReferenceToPrimaryKey(false);
}
String propertyRef = value.getReferencedPropertyName();
if (propertyRef != null) {
buildingContext.getMetadataCollector().addUniquePropertyReference(value.getReferencedEntityName(), propertyRef);
}
} else {
throw new AnnotationException("Referenced property not a (One|Many)ToOne: " + StringHelper.qualify(otherSide.getEntityName(), mappedBy) + " in mappedBy of " + StringHelper.qualify(ownerEntity, ownerProperty));
}
}
final ForeignKey fk = inferredData.getProperty().getAnnotation(ForeignKey.class);
if (fk != null && !BinderHelper.isEmptyAnnotationValue(fk.name())) {
value.setForeignKeyName(fk.name());
} else {
final javax.persistence.ForeignKey jpaFk = inferredData.getProperty().getAnnotation(javax.persistence.ForeignKey.class);
if (jpaFk != null) {
if (jpaFk.value() == ConstraintMode.NO_CONSTRAINT) {
value.setForeignKeyName("none");
} else {
value.setForeignKeyName(StringHelper.nullIfEmpty(jpaFk.name()));
value.setForeignKeyDefinition(StringHelper.nullIfEmpty(jpaFk.foreignKeyDefinition()));
}
}
}
}
use of org.hibernate.annotations.ForeignKey in project hibernate-orm by hibernate.
the class AnnotationBinder method bindManyToOne.
private static void bindManyToOne(String cascadeStrategy, Ejb3JoinColumn[] columns, boolean optional, boolean ignoreNotFound, boolean cascadeOnDelete, XClass targetEntity, PropertyHolder propertyHolder, PropertyData inferredData, boolean unique, boolean isIdentifierMapper, boolean inSecondPass, PropertyBinder propertyBinder, MetadataBuildingContext context) {
// All FK columns should be in the same table
org.hibernate.mapping.ManyToOne value = new org.hibernate.mapping.ManyToOne(context, columns[0].getTable());
// This is a @OneToOne mapped to a physical o.h.mapping.ManyToOne
if (unique) {
value.markAsLogicalOneToOne();
}
value.setReferencedEntityName(ToOneBinder.getReferenceEntityName(inferredData, targetEntity, context));
final XProperty property = inferredData.getProperty();
defineFetchingStrategy(value, property);
// value.setFetchMode( fetchMode );
value.setIgnoreNotFound(ignoreNotFound);
value.setCascadeDeleteEnabled(cascadeOnDelete);
// value.setLazy( fetchMode != FetchMode.JOIN );
if (!optional) {
for (Ejb3JoinColumn column : columns) {
column.setNullable(false);
}
}
if (property.isAnnotationPresent(MapsId.class)) {
// read only
for (Ejb3JoinColumn column : columns) {
column.setInsertable(false);
column.setUpdatable(false);
}
}
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
boolean hasSpecjManyToOne = false;
if (context.getBuildingOptions().isSpecjProprietarySyntaxEnabled()) {
String columnName = "";
for (XProperty prop : inferredData.getDeclaringClass().getDeclaredProperties(AccessType.FIELD.getType())) {
if (prop.isAnnotationPresent(Id.class) && prop.isAnnotationPresent(Column.class)) {
columnName = prop.getAnnotation(Column.class).name();
}
if (property.isAnnotationPresent(ManyToOne.class) && joinColumn != null && !BinderHelper.isEmptyAnnotationValue(joinColumn.name()) && joinColumn.name().equals(columnName) && !property.isAnnotationPresent(MapsId.class)) {
hasSpecjManyToOne = true;
for (Ejb3JoinColumn column : columns) {
column.setInsertable(false);
column.setUpdatable(false);
}
}
}
}
value.setTypeName(inferredData.getClassOrElementName());
final String propertyName = inferredData.getPropertyName();
value.setTypeUsingReflection(propertyHolder.getClassName(), propertyName);
if ((joinColumn != null && joinColumn.foreignKey().value() == ConstraintMode.NO_CONSTRAINT) || (joinColumns != null && joinColumns.foreignKey().value() == ConstraintMode.NO_CONSTRAINT)) {
// not ideal...
value.setForeignKeyName("none");
} else {
final ForeignKey fk = property.getAnnotation(ForeignKey.class);
if (fk != null && StringHelper.isNotEmpty(fk.name())) {
value.setForeignKeyName(fk.name());
} else {
final javax.persistence.ForeignKey fkOverride = propertyHolder.getOverriddenForeignKey(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()));
}
}
}
String path = propertyHolder.getPath() + "." + propertyName;
FkSecondPass secondPass = new ToOneFkSecondPass(value, columns, // cannot have nullable and unique on certain DBs like Derby
!optional && unique, propertyHolder.getEntityOwnerClassName(), path, context);
if (inSecondPass) {
secondPass.doSecondPass(context.getMetadataCollector().getEntityBindingMap());
} else {
context.getMetadataCollector().addSecondPass(secondPass);
}
Ejb3Column.checkPropertyConsistency(columns, propertyHolder.getEntityName() + "." + propertyName);
// PropertyBinder binder = new PropertyBinder();
propertyBinder.setName(propertyName);
propertyBinder.setValue(value);
// binder.setCascade(cascadeStrategy);
if (isIdentifierMapper) {
propertyBinder.setInsertable(false);
propertyBinder.setUpdatable(false);
} else if (hasSpecjManyToOne) {
propertyBinder.setInsertable(false);
propertyBinder.setUpdatable(false);
} else {
propertyBinder.setInsertable(columns[0].isInsertable());
propertyBinder.setUpdatable(columns[0].isUpdatable());
}
propertyBinder.setColumns(columns);
propertyBinder.setAccessType(inferredData.getDefaultAccess());
propertyBinder.setCascade(cascadeStrategy);
propertyBinder.setProperty(property);
propertyBinder.setXToMany(true);
propertyBinder.makePropertyAndBind();
}
Aggregations