Search in sources :

Example 1 with JoinColumns

use of jakarta.persistence.JoinColumns in project hibernate-orm by hibernate.

the class AnnotationBinder method bindCollection.

private static void bindCollection(PropertyHolder propertyHolder, Nullability nullability, PropertyData inferredData, Map<String, IdentifierGeneratorDefinition> classGenerators, EntityBinder entityBinder, boolean isIdentifierMapper, MetadataBuildingContext context, Map<XClass, InheritanceState> inheritanceStatePerClass, XProperty property, AnnotatedJoinColumn[] joinColumns) {
    OneToMany oneToManyAnn = property.getAnnotation(OneToMany.class);
    ManyToMany manyToManyAnn = property.getAnnotation(ManyToMany.class);
    ElementCollection elementCollectionAnn = property.getAnnotation(ElementCollection.class);
    if ((oneToManyAnn != null || manyToManyAnn != null || elementCollectionAnn != null) && isToManyAssociationWithinEmbeddableCollection(propertyHolder)) {
        throw new AnnotationException("@OneToMany, @ManyToMany or @ElementCollection cannot be used inside an @Embeddable that is also contained within an @ElementCollection: " + BinderHelper.getPath(propertyHolder, inferredData));
    }
    if (property.isAnnotationPresent(OrderColumn.class) && manyToManyAnn != null && !manyToManyAnn.mappedBy().isEmpty()) {
        throw new AnnotationException("Explicit @OrderColumn on inverse side of @ManyToMany is illegal: " + BinderHelper.getPath(propertyHolder, inferredData));
    }
    final IndexColumn indexColumn = IndexColumn.fromAnnotations(property.getAnnotation(OrderColumn.class), property.getAnnotation(org.hibernate.annotations.IndexColumn.class), property.getAnnotation(ListIndexBase.class), propertyHolder, inferredData, entityBinder.getSecondaryTables(), context);
    CollectionBinder collectionBinder = getCollectionBinder(property, hasMapKeyAnnotation(property), context);
    collectionBinder.setIndexColumn(indexColumn);
    collectionBinder.setMapKey(property.getAnnotation(MapKey.class));
    collectionBinder.setPropertyName(inferredData.getPropertyName());
    collectionBinder.setBatchSize(property.getAnnotation(BatchSize.class));
    collectionBinder.setJpaOrderBy(property.getAnnotation(jakarta.persistence.OrderBy.class));
    collectionBinder.setSqlOrderBy(getOverridableAnnotation(property, OrderBy.class, context));
    collectionBinder.setNaturalSort(property.getAnnotation(SortNatural.class));
    collectionBinder.setComparatorSort(property.getAnnotation(SortComparator.class));
    collectionBinder.setCache(property.getAnnotation(Cache.class));
    collectionBinder.setPropertyHolder(propertyHolder);
    Cascade hibernateCascade = property.getAnnotation(Cascade.class);
    NotFound notFound = property.getAnnotation(NotFound.class);
    collectionBinder.setIgnoreNotFound(notFound != null && notFound.action() == NotFoundAction.IGNORE);
    collectionBinder.setCollectionType(inferredData.getProperty().getElementClass());
    collectionBinder.setAccessType(inferredData.getDefaultAccess());
    AnnotatedColumn[] elementColumns;
    // do not use "element" if you are a JPA 2 @ElementCollection, only for legacy Hibernate mappings
    PropertyData virtualProperty = property.isAnnotationPresent(ElementCollection.class) ? inferredData : new WrappedInferredData(inferredData, "element");
    Comment comment = property.getAnnotation(Comment.class);
    if (property.isAnnotationPresent(Column.class)) {
        elementColumns = buildColumnFromAnnotation(property.getAnnotation(Column.class), comment, nullability, propertyHolder, virtualProperty, entityBinder.getSecondaryTables(), context);
    } else if (property.isAnnotationPresent(Formula.class)) {
        elementColumns = buildFormulaFromAnnotation(getOverridableAnnotation(property, Formula.class, context), comment, nullability, propertyHolder, virtualProperty, entityBinder.getSecondaryTables(), context);
    } else if (property.isAnnotationPresent(Columns.class)) {
        elementColumns = buildColumnsFromAnnotations(property.getAnnotation(Columns.class).columns(), comment, nullability, propertyHolder, virtualProperty, entityBinder.getSecondaryTables(), context);
    } else {
        elementColumns = buildColumnFromNoAnnotation(comment, nullability, propertyHolder, virtualProperty, entityBinder.getSecondaryTables(), context);
    }
    JoinColumn[] joinKeyColumns = mapKeyColumns(propertyHolder, inferredData, entityBinder, context, property, collectionBinder, comment);
    AnnotatedJoinColumn[] mapJoinColumns = buildJoinColumnsWithDefaultColumnSuffix(joinKeyColumns, comment, null, entityBinder.getSecondaryTables(), propertyHolder, inferredData.getPropertyName(), "_KEY", context);
    collectionBinder.setMapKeyManyToManyColumns(mapJoinColumns);
    // potential element
    collectionBinder.setEmbedded(property.isAnnotationPresent(Embedded.class));
    collectionBinder.setElementColumns(elementColumns);
    collectionBinder.setProperty(property);
    // TODO enhance exception with @ManyToAny and @CollectionOfElements
    if (oneToManyAnn != null && manyToManyAnn != null) {
        throw new AnnotationException("@OneToMany and @ManyToMany on the same property is not allowed: " + propertyHolder.getEntityName() + "." + inferredData.getPropertyName());
    }
    String mappedBy = null;
    ReflectionManager reflectionManager = context.getBootstrapContext().getReflectionManager();
    if (oneToManyAnn != null) {
        for (AnnotatedJoinColumn column : joinColumns) {
            if (column.isSecondary()) {
                throw new NotYetImplementedException("Collections having FK in secondary table");
            }
        }
        collectionBinder.setFkJoinColumns(joinColumns);
        mappedBy = oneToManyAnn.mappedBy();
        // noinspection unchecked
        collectionBinder.setTargetEntity(reflectionManager.toXClass(oneToManyAnn.targetEntity()));
        collectionBinder.setCascadeStrategy(getCascadeStrategy(oneToManyAnn.cascade(), hibernateCascade, oneToManyAnn.orphanRemoval(), false));
        collectionBinder.setOneToMany(true);
    } else if (elementCollectionAnn != null) {
        for (AnnotatedJoinColumn column : joinColumns) {
            if (column.isSecondary()) {
                throw new NotYetImplementedException("Collections having FK in secondary table");
            }
        }
        collectionBinder.setFkJoinColumns(joinColumns);
        mappedBy = "";
        final Class<?> targetElement = elementCollectionAnn.targetClass();
        collectionBinder.setTargetEntity(reflectionManager.toXClass(targetElement));
        // collectionBinder.setCascadeStrategy( getCascadeStrategy( embeddedCollectionAnn.cascade(), hibernateCascade ) );
        collectionBinder.setOneToMany(true);
    } else if (manyToManyAnn != null) {
        mappedBy = manyToManyAnn.mappedBy();
        // noinspection unchecked
        collectionBinder.setTargetEntity(reflectionManager.toXClass(manyToManyAnn.targetEntity()));
        collectionBinder.setCascadeStrategy(getCascadeStrategy(manyToManyAnn.cascade(), hibernateCascade, false, false));
        collectionBinder.setOneToMany(false);
    } else if (property.isAnnotationPresent(ManyToAny.class)) {
        mappedBy = "";
        collectionBinder.setTargetEntity(reflectionManager.toXClass(void.class));
        collectionBinder.setCascadeStrategy(getCascadeStrategy(null, hibernateCascade, false, false));
        collectionBinder.setOneToMany(false);
    }
    collectionBinder.setMappedBy(mappedBy);
    bindJoinedTableAssociation(property, context, entityBinder, collectionBinder, propertyHolder, inferredData, mappedBy);
    OnDelete onDeleteAnn = property.getAnnotation(OnDelete.class);
    boolean onDeleteCascade = onDeleteAnn != null && OnDeleteAction.CASCADE == onDeleteAnn.action();
    collectionBinder.setCascadeDeleteEnabled(onDeleteCascade);
    if (isIdentifierMapper) {
        collectionBinder.setInsertable(false);
        collectionBinder.setUpdatable(false);
    }
    if (property.isAnnotationPresent(CollectionId.class)) {
        // do not compute the generators unless necessary
        HashMap<String, IdentifierGeneratorDefinition> localGenerators = new HashMap<>(classGenerators);
        localGenerators.putAll(buildGenerators(property, context));
        collectionBinder.setLocalGenerators(localGenerators);
    }
    collectionBinder.setInheritanceStatePerClass(inheritanceStatePerClass);
    collectionBinder.setDeclaringClass(inferredData.getDeclaringClass());
    collectionBinder.bind();
}
Also used : HashMap(java.util.HashMap) SortNatural(org.hibernate.annotations.SortNatural) ManyToAny(org.hibernate.annotations.ManyToAny) Formula(org.hibernate.annotations.Formula) DiscriminatorFormula(org.hibernate.annotations.DiscriminatorFormula) MapKeyJoinColumn(jakarta.persistence.MapKeyJoinColumn) JoinColumn(jakarta.persistence.JoinColumn) PrimaryKeyJoinColumn(jakarta.persistence.PrimaryKeyJoinColumn) AnnotationException(org.hibernate.AnnotationException) SortComparator(org.hibernate.annotations.SortComparator) ElementCollection(jakarta.persistence.ElementCollection) Embedded(jakarta.persistence.Embedded) Cascade(org.hibernate.annotations.Cascade) OrderBy(org.hibernate.annotations.OrderBy) BatchSize(org.hibernate.annotations.BatchSize) Comment(org.hibernate.annotations.Comment) ReflectionManager(org.hibernate.annotations.common.reflection.ReflectionManager) OrderColumn(jakarta.persistence.OrderColumn) ManyToMany(jakarta.persistence.ManyToMany) AnnotatedJoinColumn.buildJoinTableJoinColumns(org.hibernate.cfg.AnnotatedJoinColumn.buildJoinTableJoinColumns) JoinColumns(jakarta.persistence.JoinColumns) PrimaryKeyJoinColumns(jakarta.persistence.PrimaryKeyJoinColumns) Columns(org.hibernate.annotations.Columns) MapKeyJoinColumns(jakarta.persistence.MapKeyJoinColumns) ListIndexBase(org.hibernate.annotations.ListIndexBase) OneToMany(jakarta.persistence.OneToMany) MapKey(jakarta.persistence.MapKey) IdentifierGeneratorDefinition(org.hibernate.boot.model.IdentifierGeneratorDefinition) XClass(org.hibernate.annotations.common.reflection.XClass) RootClass(org.hibernate.mapping.RootClass) PersistentClass(org.hibernate.mapping.PersistentClass) IdClass(jakarta.persistence.IdClass) CollectionBinder(org.hibernate.cfg.annotations.CollectionBinder) CollectionBinder.getCollectionBinder(org.hibernate.cfg.annotations.CollectionBinder.getCollectionBinder) Cache(org.hibernate.annotations.Cache) NotFound(org.hibernate.annotations.NotFound) OnDelete(org.hibernate.annotations.OnDelete)

Example 2 with JoinColumns

use of jakarta.persistence.JoinColumns in project hibernate-orm by hibernate.

the class AnnotationBinder method bindManyToOne.

private static void bindManyToOne(PropertyHolder propertyHolder, PropertyData inferredData, boolean isIdentifierMapper, boolean inSecondPass, MetadataBuildingContext context, XProperty property, AnnotatedJoinColumn[] joinColumns, PropertyBinder propertyBinder, boolean forcePersist) {
    ManyToOne ann = property.getAnnotation(ManyToOne.class);
    // check validity
    if (property.isAnnotationPresent(Column.class) || property.isAnnotationPresent(Columns.class)) {
        throw new AnnotationException("@Column(s) not allowed on a @ManyToOne property: " + BinderHelper.getPath(propertyHolder, inferredData));
    }
    Cascade hibernateCascade = property.getAnnotation(Cascade.class);
    NotFound notFound = property.getAnnotation(NotFound.class);
    boolean ignoreNotFound = notFound != null && notFound.action() == NotFoundAction.IGNORE;
    matchIgnoreNotFoundWithFetchType(propertyHolder.getEntityName(), property.getName(), ignoreNotFound, ann.fetch());
    OnDelete onDeleteAnn = property.getAnnotation(OnDelete.class);
    JoinTable assocTable = propertyHolder.getJoinTable(property);
    if (assocTable != null) {
        Join join = propertyHolder.addJoin(assocTable, false);
        for (AnnotatedJoinColumn joinColumn : joinColumns) {
            joinColumn.setExplicitTableName(join.getTable().getName());
        }
    }
    // MapsId means the columns belong to the pk;
    // A @MapsId association (obviously) must be non-null when the entity is first persisted.
    // If a @MapsId association is not mapped with @NotFound(IGNORE), then the association
    // is mandatory (even if the association has optional=true).
    // If a @MapsId association has optional=true and is mapped with @NotFound(IGNORE) then
    // the association is optional.
    final boolean mandatory = !ann.optional() || property.isAnnotationPresent(Id.class) || property.isAnnotationPresent(MapsId.class) && !ignoreNotFound;
    bindManyToOne(getCascadeStrategy(ann.cascade(), hibernateCascade, false, forcePersist), joinColumns, !mandatory, ignoreNotFound, onDeleteAnn != null && OnDeleteAction.CASCADE == onDeleteAnn.action(), ToOneBinder.getTargetEntity(inferredData, context), propertyHolder, inferredData, false, isIdentifierMapper, inSecondPass, propertyBinder, context);
}
Also used : MapKeyColumn(jakarta.persistence.MapKeyColumn) MapKeyJoinColumn(jakarta.persistence.MapKeyJoinColumn) JoinColumn(jakarta.persistence.JoinColumn) Column(jakarta.persistence.Column) PrimaryKeyJoinColumn(jakarta.persistence.PrimaryKeyJoinColumn) OrderColumn(jakarta.persistence.OrderColumn) DiscriminatorColumn(jakarta.persistence.DiscriminatorColumn) AnnotatedDiscriminatorColumn.buildDiscriminatorColumn(org.hibernate.cfg.AnnotatedDiscriminatorColumn.buildDiscriminatorColumn) AnnotatedJoinColumn.buildJoinTableJoinColumns(org.hibernate.cfg.AnnotatedJoinColumn.buildJoinTableJoinColumns) JoinColumns(jakarta.persistence.JoinColumns) PrimaryKeyJoinColumns(jakarta.persistence.PrimaryKeyJoinColumns) Columns(org.hibernate.annotations.Columns) MapKeyJoinColumns(jakarta.persistence.MapKeyJoinColumns) AnnotationException(org.hibernate.AnnotationException) Join(org.hibernate.mapping.Join) ManyToOne(jakarta.persistence.ManyToOne) Cascade(org.hibernate.annotations.Cascade) NotFound(org.hibernate.annotations.NotFound) OnDelete(org.hibernate.annotations.OnDelete) JoinTable(jakarta.persistence.JoinTable)

Example 3 with JoinColumns

use of jakarta.persistence.JoinColumns in project hibernate-orm by hibernate.

the class ColumnsBuilder method buildExplicitJoinColumns.

AnnotatedJoinColumn[] buildExplicitJoinColumns(XProperty property, PropertyData inferredData) {
    // process @JoinColumn(s) before @Column(s) to handle collection of entities properly
    JoinColumn[] joinColumnAnnotations = null;
    if (property.isAnnotationPresent(JoinColumn.class)) {
        joinColumnAnnotations = new JoinColumn[] { property.getAnnotation(JoinColumn.class) };
    } else if (property.isAnnotationPresent(JoinColumns.class)) {
        JoinColumns joinColumnAnnotation = property.getAnnotation(JoinColumns.class);
        joinColumnAnnotations = joinColumnAnnotation.value();
        int length = joinColumnAnnotations.length;
        if (length == 0) {
            throw new AnnotationException("Cannot bind an empty @JoinColumns");
        }
    }
    if (joinColumnAnnotations != null) {
        return AnnotatedJoinColumn.buildJoinColumns(joinColumnAnnotations, property.getAnnotation(Comment.class), null, entityBinder.getSecondaryTables(), propertyHolder, inferredData.getPropertyName(), buildingContext);
    }
    JoinColumnOrFormula[] joinColumnOrFormulaAnnotations = null;
    if (property.isAnnotationPresent(JoinColumnOrFormula.class)) {
        joinColumnOrFormulaAnnotations = new JoinColumnOrFormula[] { property.getAnnotation(JoinColumnOrFormula.class) };
    } else if (property.isAnnotationPresent(JoinColumnsOrFormulas.class)) {
        JoinColumnsOrFormulas joinColumnsOrFormulasAnnotations = property.getAnnotation(JoinColumnsOrFormulas.class);
        joinColumnOrFormulaAnnotations = joinColumnsOrFormulasAnnotations.value();
        int length = joinColumnOrFormulaAnnotations.length;
        if (length == 0) {
            throw new AnnotationException("Cannot bind an empty @JoinColumnsOrFormulas");
        }
    }
    if (joinColumnOrFormulaAnnotations != null) {
        return AnnotatedJoinColumn.buildJoinColumnsOrFormulas(joinColumnOrFormulaAnnotations, null, entityBinder.getSecondaryTables(), propertyHolder, inferredData.getPropertyName(), buildingContext);
    }
    if (property.isAnnotationPresent(JoinFormula.class)) {
        JoinFormula ann = getOverridableAnnotation(property, JoinFormula.class, buildingContext);
        AnnotatedJoinColumn[] annotatedJoinColumns = new AnnotatedJoinColumn[1];
        annotatedJoinColumns[0] = AnnotatedJoinColumn.buildJoinFormula(ann, null, entityBinder.getSecondaryTables(), propertyHolder, inferredData.getPropertyName(), buildingContext);
        return annotatedJoinColumns;
    }
    return null;
}
Also used : Comment(org.hibernate.annotations.Comment) JoinFormula(org.hibernate.annotations.JoinFormula) JoinColumn(jakarta.persistence.JoinColumn) JoinColumnOrFormula(org.hibernate.annotations.JoinColumnOrFormula) JoinColumns(jakarta.persistence.JoinColumns) AnnotationException(org.hibernate.AnnotationException) JoinColumnsOrFormulas(org.hibernate.annotations.JoinColumnsOrFormulas)

Example 4 with JoinColumns

use of jakarta.persistence.JoinColumns in project hibernate-orm by hibernate.

the class JPAXMLOverriddenAnnotationReader method overridesDefaultsInJoinTable.

private JoinTable overridesDefaultsInJoinTable(Annotation annotation, XMLContext.Default defaults) {
    // no element but might have some default or some annotation
    boolean defaultToJoinTable = !(isPhysicalAnnotationPresent(JoinColumn.class) || isPhysicalAnnotationPresent(JoinColumns.class));
    final Class<? extends Annotation> annotationClass = annotation.annotationType();
    defaultToJoinTable = defaultToJoinTable && ((annotationClass == ManyToMany.class && StringHelper.isEmpty(((ManyToMany) annotation).mappedBy())) || (annotationClass == OneToMany.class && StringHelper.isEmpty(((OneToMany) annotation).mappedBy())) || (annotationClass == ElementCollection.class));
    final Class<JoinTable> annotationType = JoinTable.class;
    if (defaultToJoinTable && (StringHelper.isNotEmpty(defaults.getCatalog()) || StringHelper.isNotEmpty(defaults.getSchema()))) {
        AnnotationDescriptor ad = new AnnotationDescriptor(annotationType);
        if (defaults.canUseJavaAnnotations()) {
            JoinTable table = getPhysicalAnnotation(annotationType);
            if (table != null) {
                ad.setValue("name", table.name());
                ad.setValue("schema", table.schema());
                ad.setValue("catalog", table.catalog());
                ad.setValue("uniqueConstraints", table.uniqueConstraints());
                ad.setValue("joinColumns", table.joinColumns());
                ad.setValue("inverseJoinColumns", table.inverseJoinColumns());
            }
        }
        if (StringHelper.isEmpty((String) ad.valueOf("schema")) && StringHelper.isNotEmpty(defaults.getSchema())) {
            ad.setValue("schema", defaults.getSchema());
        }
        if (StringHelper.isEmpty((String) ad.valueOf("catalog")) && StringHelper.isNotEmpty(defaults.getCatalog())) {
            ad.setValue("catalog", defaults.getCatalog());
        }
        return AnnotationFactory.create(ad);
    } else if (defaults.canUseJavaAnnotations()) {
        return getPhysicalAnnotation(annotationType);
    } else {
        return null;
    }
}
Also used : AnnotationDescriptor(org.hibernate.annotations.common.annotationfactory.AnnotationDescriptor) JaxbPrimaryKeyJoinColumn(org.hibernate.boot.jaxb.mapping.spi.JaxbPrimaryKeyJoinColumn) JaxbMapKeyJoinColumn(org.hibernate.boot.jaxb.mapping.spi.JaxbMapKeyJoinColumn) PrimaryKeyJoinColumn(jakarta.persistence.PrimaryKeyJoinColumn) MapKeyJoinColumn(jakarta.persistence.MapKeyJoinColumn) JoinColumn(jakarta.persistence.JoinColumn) JaxbJoinColumn(org.hibernate.boot.jaxb.mapping.spi.JaxbJoinColumn) PrimaryKeyJoinColumns(jakarta.persistence.PrimaryKeyJoinColumns) MapKeyJoinColumns(jakarta.persistence.MapKeyJoinColumns) JoinColumns(jakarta.persistence.JoinColumns) ManyToMany(jakarta.persistence.ManyToMany) JaxbManyToMany(org.hibernate.boot.jaxb.mapping.spi.JaxbManyToMany) ElementCollection(jakarta.persistence.ElementCollection) JaxbElementCollection(org.hibernate.boot.jaxb.mapping.spi.JaxbElementCollection) JaxbOneToMany(org.hibernate.boot.jaxb.mapping.spi.JaxbOneToMany) OneToMany(jakarta.persistence.OneToMany) JaxbJoinTable(org.hibernate.boot.jaxb.mapping.spi.JaxbJoinTable) JoinTable(jakarta.persistence.JoinTable)

Example 5 with JoinColumns

use of jakarta.persistence.JoinColumns 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<String, PersistentClass> persistentClasses) throws MappingException {
    OneToOne value = new 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);
    // value.setLazy( fetchMode != FetchMode.JOIN );
    value.setConstrained(!optional);
    final ForeignKeyDirection foreignKeyDirection = !BinderHelper.isEmptyAnnotationValue(mappedBy) ? ForeignKeyDirection.TO_PARENT : ForeignKeyDirection.FROM_PARENT;
    value.setForeignKeyType(foreignKeyDirection);
    AnnotationBinder.bindForeignKeyNameAndDefinition(value, inferredData.getProperty(), inferredData.getProperty().getAnnotation(jakarta.persistence.ForeignKey.class), inferredData.getProperty().getAnnotation(JoinColumn.class), inferredData.getProperty().getAnnotation(JoinColumns.class), buildingContext);
    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 {
        value.setMappedByProperty(mappedBy);
        PersistentClass otherSide = 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) {
            Join otherSideJoin = null;
            for (Join otherSideJoinValue : otherSide.getJoins()) {
                if (otherSideJoinValue.containsProperty(otherSideProperty)) {
                    otherSideJoin = otherSideJoinValue;
                    break;
                }
            }
            if (otherSideJoin != null) {
                // @OneToOne @JoinTable
                Join mappedByJoin = buildJoinFromMappedBySide(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());
                manyToOne.markAsLogicalOneToOne();
                prop.setValue(manyToOne);
                for (Column column : otherSideJoin.getKey().getColumns()) {
                    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());
                    copy.setGeneratedAs(column.getGeneratedAs());
                    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);
            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));
        }
    }
    value.sortProperties();
}
Also used : JoinColumns(jakarta.persistence.JoinColumns) Join(org.hibernate.mapping.Join) ForeignKeyDirection(org.hibernate.type.ForeignKeyDirection) ManyToOne(org.hibernate.mapping.ManyToOne) MappingException(org.hibernate.MappingException) OneToOne(org.hibernate.mapping.OneToOne) JoinColumn(jakarta.persistence.JoinColumn) Column(org.hibernate.mapping.Column) JoinColumn(jakarta.persistence.JoinColumn) LazyGroup(org.hibernate.annotations.LazyGroup) AnnotationException(org.hibernate.AnnotationException) PropertyBinder(org.hibernate.cfg.annotations.PropertyBinder) Component(org.hibernate.mapping.Component) Property(org.hibernate.mapping.Property) PersistentClass(org.hibernate.mapping.PersistentClass)

Aggregations

JoinColumns (jakarta.persistence.JoinColumns)15 JoinColumn (jakarta.persistence.JoinColumn)14 MapKeyJoinColumn (jakarta.persistence.MapKeyJoinColumn)8 MapKeyJoinColumns (jakarta.persistence.MapKeyJoinColumns)8 PrimaryKeyJoinColumn (jakarta.persistence.PrimaryKeyJoinColumn)8 PrimaryKeyJoinColumns (jakarta.persistence.PrimaryKeyJoinColumns)8 AnnotationException (org.hibernate.AnnotationException)6 Test (org.junit.Test)6 OrderColumn (jakarta.persistence.OrderColumn)5 AnnotatedJoinColumn.buildJoinTableJoinColumns (org.hibernate.cfg.AnnotatedJoinColumn.buildJoinTableJoinColumns)5 Column (jakarta.persistence.Column)4 DiscriminatorColumn (jakarta.persistence.DiscriminatorColumn)4 MapKeyColumn (jakarta.persistence.MapKeyColumn)4 Columns (org.hibernate.annotations.Columns)4 JoinTable (jakarta.persistence.JoinTable)3 ManyToOne (jakarta.persistence.ManyToOne)3 OneToMany (jakarta.persistence.OneToMany)3 Cascade (org.hibernate.annotations.Cascade)3 Comment (org.hibernate.annotations.Comment)3 NotFound (org.hibernate.annotations.NotFound)3