Search in sources :

Example 66 with Collection

use of org.hibernate.mapping.Collection in project hibernate-orm by hibernate.

the class TableBinder method bindFk.

public static void bindFk(PersistentClass referencedEntity, PersistentClass destinationEntity, Ejb3JoinColumn[] columns, SimpleValue value, boolean unique, MetadataBuildingContext buildingContext) {
    PersistentClass associatedClass;
    if (destinationEntity != null) {
        // overridden destination
        associatedClass = destinationEntity;
    } else {
        associatedClass = columns[0].getPropertyHolder() == null ? null : columns[0].getPropertyHolder().getPersistentClass();
    }
    final String mappedByProperty = columns[0].getMappedBy();
    if (StringHelper.isNotEmpty(mappedByProperty)) {
        /**
         * Get the columns of the mapped-by property
         * copy them and link the copy to the actual value
         */
        LOG.debugf("Retrieving property %s.%s", associatedClass.getEntityName(), mappedByProperty);
        final Property property = associatedClass.getRecursiveProperty(columns[0].getMappedBy());
        Iterator mappedByColumns;
        if (property.getValue() instanceof Collection) {
            Collection collection = ((Collection) property.getValue());
            Value element = collection.getElement();
            if (element == null) {
                throw new AnnotationException("Illegal use of mappedBy on both sides of the relationship: " + associatedClass.getEntityName() + "." + mappedByProperty);
            }
            mappedByColumns = element.getColumnIterator();
        } else {
            mappedByColumns = property.getValue().getColumnIterator();
        }
        while (mappedByColumns.hasNext()) {
            Column column = (Column) mappedByColumns.next();
            columns[0].overrideFromReferencedColumnIfNecessary(column);
            columns[0].linkValueUsingAColumnCopy(column, value);
        }
    } else if (columns[0].isImplicit()) {
        /**
         * if columns are implicit, then create the columns based on the
         * referenced entity id columns
         */
        Iterator idColumns;
        if (referencedEntity instanceof JoinedSubclass) {
            idColumns = referencedEntity.getKey().getColumnIterator();
        } else {
            idColumns = referencedEntity.getIdentifier().getColumnIterator();
        }
        while (idColumns.hasNext()) {
            Column column = (Column) idColumns.next();
            columns[0].linkValueUsingDefaultColumnNaming(column, referencedEntity, value);
            columns[0].overrideFromReferencedColumnIfNecessary(column);
        }
    } else {
        int fkEnum = Ejb3JoinColumn.checkReferencedColumnsType(columns, referencedEntity, buildingContext);
        if (Ejb3JoinColumn.NON_PK_REFERENCE == fkEnum) {
            String referencedPropertyName;
            if (value instanceof ToOne) {
                referencedPropertyName = ((ToOne) value).getReferencedPropertyName();
            } else if (value instanceof DependantValue) {
                String propertyName = columns[0].getPropertyName();
                if (propertyName != null) {
                    Collection collection = (Collection) referencedEntity.getRecursiveProperty(propertyName).getValue();
                    referencedPropertyName = collection.getReferencedPropertyName();
                } else {
                    throw new AnnotationException("SecondaryTable JoinColumn cannot reference a non primary key");
                }
            } else {
                throw new AssertionFailure("Do a property ref on an unexpected Value type: " + value.getClass().getName());
            }
            if (referencedPropertyName == null) {
                throw new AssertionFailure("No property ref found while expected");
            }
            Property synthProp = referencedEntity.getReferencedProperty(referencedPropertyName);
            if (synthProp == null) {
                throw new AssertionFailure("Cannot find synthProp: " + referencedEntity.getEntityName() + "." + referencedPropertyName);
            }
            linkJoinColumnWithValueOverridingNameIfImplicit(referencedEntity, synthProp.getColumnIterator(), columns, value);
        } else {
            if (Ejb3JoinColumn.NO_REFERENCE == fkEnum) {
                // implicit case, we hope PK and FK columns are in the same order
                if (columns.length != referencedEntity.getIdentifier().getColumnSpan()) {
                    throw new AnnotationException("A Foreign key refering " + referencedEntity.getEntityName() + " from " + associatedClass.getEntityName() + " has the wrong number of column. should be " + referencedEntity.getIdentifier().getColumnSpan());
                }
                linkJoinColumnWithValueOverridingNameIfImplicit(referencedEntity, referencedEntity.getIdentifier().getColumnIterator(), columns, value);
            } else {
                // explicit referencedColumnName
                Iterator idColItr = referencedEntity.getKey().getColumnIterator();
                org.hibernate.mapping.Column col;
                // works cause the pk has to be on the primary table
                Table table = referencedEntity.getTable();
                if (!idColItr.hasNext()) {
                    LOG.debug("No column in the identifier!");
                }
                while (idColItr.hasNext()) {
                    boolean match = false;
                    // for each PK column, find the associated FK column.
                    col = (org.hibernate.mapping.Column) idColItr.next();
                    for (Ejb3JoinColumn joinCol : columns) {
                        String referencedColumn = joinCol.getReferencedColumn();
                        referencedColumn = buildingContext.getMetadataCollector().getPhysicalColumnName(table, referencedColumn);
                        // In JPA 2 referencedColumnName is case insensitive
                        if (referencedColumn.equalsIgnoreCase(col.getQuotedName(buildingContext.getMetadataCollector().getDatabase().getJdbcEnvironment().getDialect()))) {
                            // proper join column
                            if (joinCol.isNameDeferred()) {
                                joinCol.linkValueUsingDefaultColumnNaming(col, referencedEntity, value);
                            } else {
                                joinCol.linkWithValue(value);
                            }
                            joinCol.overrideFromReferencedColumnIfNecessary(col);
                            match = true;
                            break;
                        }
                    }
                    if (!match) {
                        throw new AnnotationException("Column name " + col.getName() + " of " + referencedEntity.getEntityName() + " not found in JoinColumns.referencedColumnName");
                    }
                }
            }
        }
    }
    value.createForeignKey();
    if (unique) {
        createUniqueConstraint(value);
    }
}
Also used : AssertionFailure(org.hibernate.AssertionFailure) Table(org.hibernate.mapping.Table) DependantValue(org.hibernate.mapping.DependantValue) Column(org.hibernate.mapping.Column) Ejb3JoinColumn(org.hibernate.cfg.Ejb3JoinColumn) Iterator(java.util.Iterator) SimpleValue(org.hibernate.mapping.SimpleValue) DependantValue(org.hibernate.mapping.DependantValue) Value(org.hibernate.mapping.Value) ToOne(org.hibernate.mapping.ToOne) Collection(org.hibernate.mapping.Collection) AnnotationException(org.hibernate.AnnotationException) Ejb3JoinColumn(org.hibernate.cfg.Ejb3JoinColumn) JoinedSubclass(org.hibernate.mapping.JoinedSubclass) Property(org.hibernate.mapping.Property) PersistentClass(org.hibernate.mapping.PersistentClass)

Example 67 with Collection

use of org.hibernate.mapping.Collection in project hibernate-orm by hibernate.

the class BinderHelper method createSyntheticPropertyReference.

// This is sooooooooo close in terms of not generating a synthetic property if we do not have to (where property ref
// refers to a single property).  The sticking point is cases where the `referencedPropertyName` come from subclasses
// or secondary tables.  Part of the problem is in PersistentClass itself during attempts to resolve the referenced
// property; currently it only considers non-subclass and non-joined properties.  Part of the problem is in terms
// of SQL generation.
// public static void createSyntheticPropertyReference(
// Ejb3JoinColumn[] columns,
// PersistentClass ownerEntity,
// PersistentClass associatedEntity,
// Value value,
// boolean inverse,
// Mappings mappings) {
// //associated entity only used for more precise exception, yuk!
// if ( columns[0].isImplicit() || StringHelper.isNotEmpty( columns[0].getMappedBy() ) ) return;
// int fkEnum = Ejb3JoinColumn.checkReferencedColumnsType( columns, ownerEntity, mappings );
// PersistentClass associatedClass = columns[0].getPropertyHolder() != null ?
// columns[0].getPropertyHolder().getPersistentClass() :
// null;
// if ( Ejb3JoinColumn.NON_PK_REFERENCE == fkEnum ) {
// //find properties associated to a certain column
// Object columnOwner = findColumnOwner( ownerEntity, columns[0].getReferencedColumn(), mappings );
// List<Property> properties = findPropertiesByColumns( columnOwner, columns, mappings );
// 
// if ( properties == null ) {
// //TODO use a ToOne type doing a second select
// StringBuilder columnsList = new StringBuilder();
// columnsList.append( "referencedColumnNames(" );
// for (Ejb3JoinColumn column : columns) {
// columnsList.append( column.getReferencedColumn() ).append( ", " );
// }
// columnsList.setLength( columnsList.length() - 2 );
// columnsList.append( ") " );
// 
// if ( associatedEntity != null ) {
// //overidden destination
// columnsList.append( "of " )
// .append( associatedEntity.getEntityName() )
// .append( "." )
// .append( columns[0].getPropertyName() )
// .append( " " );
// }
// else {
// if ( columns[0].getPropertyHolder() != null ) {
// columnsList.append( "of " )
// .append( columns[0].getPropertyHolder().getEntityName() )
// .append( "." )
// .append( columns[0].getPropertyName() )
// .append( " " );
// }
// }
// columnsList.append( "referencing " )
// .append( ownerEntity.getEntityName() )
// .append( " not mapped to a single property" );
// throw new AnnotationException( columnsList.toString() );
// }
// 
// final String referencedPropertyName;
// 
// if ( properties.size() == 1 ) {
// referencedPropertyName = properties.get(0).getName();
// }
// else {
// // Create a synthetic (embedded composite) property to use as the referenced property which
// // contains all the properties mapped to the referenced columns.  We need to make a shallow copy
// // of the properties to mark them as non-insertable/updatable.
// 
// // todo : what if the columns all match with an existing component?
// 
// StringBuilder propertyNameBuffer = new StringBuilder( "_" );
// propertyNameBuffer.append( associatedClass.getEntityName().replace( '.', '_' ) );
// propertyNameBuffer.append( "_" ).append( columns[0].getPropertyName() );
// String syntheticPropertyName = propertyNameBuffer.toString();
// //create an embeddable component
// 
// //todo how about properties.size() == 1, this should be much simpler
// Component embeddedComp = columnOwner instanceof PersistentClass ?
// new Component( mappings, (PersistentClass) columnOwner ) :
// new Component( mappings, (Join) columnOwner );
// embeddedComp.setEmbedded( true );
// embeddedComp.setNodeName( syntheticPropertyName );
// embeddedComp.setComponentClassName( embeddedComp.getOwner().getClassName() );
// for (Property property : properties) {
// Property clone = BinderHelper.shallowCopy( property );
// clone.setInsertable( false );
// clone.setUpdateable( false );
// clone.setNaturalIdentifier( false );
// clone.setGeneration( property.getGeneration() );
// embeddedComp.addProperty( clone );
// }
// SyntheticProperty synthProp = new SyntheticProperty();
// synthProp.setName( syntheticPropertyName );
// synthProp.setNodeName( syntheticPropertyName );
// synthProp.setPersistentClass( ownerEntity );
// synthProp.setUpdateable( false );
// synthProp.setInsertable( false );
// synthProp.setValue( embeddedComp );
// synthProp.setPropertyAccessorName( "embedded" );
// ownerEntity.addProperty( synthProp );
// //make it unique
// TableBinder.createUniqueConstraint( embeddedComp );
// 
// referencedPropertyName = syntheticPropertyName;
// }
// 
// /**
// * creating the property ref to the new synthetic property
// */
// if ( value instanceof ToOne ) {
// ( (ToOne) value ).setReferencedPropertyName( referencedPropertyName );
// mappings.addUniquePropertyReference( ownerEntity.getEntityName(), referencedPropertyName );
// }
// else if ( value instanceof Collection ) {
// ( (Collection) value ).setReferencedPropertyName( referencedPropertyName );
// //not unique because we could create a mtm wo association table
// mappings.addPropertyReference( ownerEntity.getEntityName(), referencedPropertyName );
// }
// else {
// throw new AssertionFailure(
// "Do a property ref on an unexpected Value type: "
// + value.getClass().getName()
// );
// }
// mappings.addPropertyReferencedAssociation(
// ( inverse ? "inverse__" : "" ) + associatedClass.getEntityName(),
// columns[0].getPropertyName(),
// referencedPropertyName
// );
// }
// }
public static void createSyntheticPropertyReference(Ejb3JoinColumn[] columns, PersistentClass ownerEntity, PersistentClass associatedEntity, Value value, boolean inverse, MetadataBuildingContext context) {
    // associated entity only used for more precise exception, yuk!
    if (columns[0].isImplicit() || StringHelper.isNotEmpty(columns[0].getMappedBy())) {
        return;
    }
    int fkEnum = Ejb3JoinColumn.checkReferencedColumnsType(columns, ownerEntity, context);
    PersistentClass associatedClass = columns[0].getPropertyHolder() != null ? columns[0].getPropertyHolder().getPersistentClass() : null;
    if (Ejb3JoinColumn.NON_PK_REFERENCE == fkEnum) {
        /**
         * Create a synthetic property to refer to including an
         * embedded component value containing all the properties
         * mapped to the referenced columns
         * We need to shallow copy those properties to mark them
         * as non insertable / non updatable
         */
        StringBuilder propertyNameBuffer = new StringBuilder("_");
        propertyNameBuffer.append(associatedClass.getEntityName().replace('.', '_'));
        propertyNameBuffer.append("_").append(columns[0].getPropertyName().replace('.', '_'));
        String syntheticPropertyName = propertyNameBuffer.toString();
        // find properties associated to a certain column
        Object columnOwner = findColumnOwner(ownerEntity, columns[0].getReferencedColumn(), context);
        List<Property> properties = findPropertiesByColumns(columnOwner, columns, context);
        // create an embeddable component
        Property synthProp;
        if (properties != null) {
            // todo how about properties.size() == 1, this should be much simpler
            Component embeddedComp = columnOwner instanceof PersistentClass ? new Component(context, (PersistentClass) columnOwner) : new Component(context, (Join) columnOwner);
            embeddedComp.setEmbedded(true);
            embeddedComp.setComponentClassName(embeddedComp.getOwner().getClassName());
            for (Property property : properties) {
                Property clone = BinderHelper.shallowCopy(property);
                clone.setInsertable(false);
                clone.setUpdateable(false);
                clone.setNaturalIdentifier(false);
                clone.setValueGenerationStrategy(property.getValueGenerationStrategy());
                embeddedComp.addProperty(clone);
            }
            synthProp = new SyntheticProperty();
            synthProp.setName(syntheticPropertyName);
            synthProp.setPersistentClass(ownerEntity);
            synthProp.setUpdateable(false);
            synthProp.setInsertable(false);
            synthProp.setValue(embeddedComp);
            synthProp.setPropertyAccessorName("embedded");
            ownerEntity.addProperty(synthProp);
            // make it unique
            TableBinder.createUniqueConstraint(embeddedComp);
        } else {
            // TODO use a ToOne type doing a second select
            StringBuilder columnsList = new StringBuilder();
            columnsList.append("referencedColumnNames(");
            for (Ejb3JoinColumn column : columns) {
                columnsList.append(column.getReferencedColumn()).append(", ");
            }
            columnsList.setLength(columnsList.length() - 2);
            columnsList.append(") ");
            if (associatedEntity != null) {
                // overidden destination
                columnsList.append("of ").append(associatedEntity.getEntityName()).append(".").append(columns[0].getPropertyName()).append(" ");
            } else {
                if (columns[0].getPropertyHolder() != null) {
                    columnsList.append("of ").append(columns[0].getPropertyHolder().getEntityName()).append(".").append(columns[0].getPropertyName()).append(" ");
                }
            }
            columnsList.append("referencing ").append(ownerEntity.getEntityName()).append(" not mapped to a single property");
            throw new AnnotationException(columnsList.toString());
        }
        /**
         * creating the property ref to the new synthetic property
         */
        if (value instanceof ToOne) {
            ((ToOne) value).setReferencedPropertyName(syntheticPropertyName);
            ((ToOne) value).setReferenceToPrimaryKey(syntheticPropertyName == null);
            context.getMetadataCollector().addUniquePropertyReference(ownerEntity.getEntityName(), syntheticPropertyName);
        } else if (value instanceof Collection) {
            ((Collection) value).setReferencedPropertyName(syntheticPropertyName);
            // not unique because we could create a mtm wo association table
            context.getMetadataCollector().addPropertyReference(ownerEntity.getEntityName(), syntheticPropertyName);
        } else {
            throw new AssertionFailure("Do a property ref on an unexpected Value type: " + value.getClass().getName());
        }
        context.getMetadataCollector().addPropertyReferencedAssociation((inverse ? "inverse__" : "") + associatedClass.getEntityName(), columns[0].getPropertyName(), syntheticPropertyName);
    }
}
Also used : AssertionFailure(org.hibernate.AssertionFailure) SyntheticProperty(org.hibernate.mapping.SyntheticProperty) Join(org.hibernate.mapping.Join) UniqueConstraint(javax.persistence.UniqueConstraint) ToOne(org.hibernate.mapping.ToOne) AnnotationException(org.hibernate.AnnotationException) Collection(org.hibernate.mapping.Collection) Component(org.hibernate.mapping.Component) Property(org.hibernate.mapping.Property) SyntheticProperty(org.hibernate.mapping.SyntheticProperty) XProperty(org.hibernate.annotations.common.reflection.XProperty) PersistentClass(org.hibernate.mapping.PersistentClass)

Example 68 with Collection

use of org.hibernate.mapping.Collection in project hibernate-orm by hibernate.

the class PersisterTest method testCollectionPersisterSpecified.

@Test
public void testCollectionPersisterSpecified() throws Exception {
    // tests the persister specified by the @Persister annotation on a collection
    Collection collection = metadata().getCollectionBinding(Deck.class.getName() + ".cards");
    assertEquals("Incorrect Persister class for collection " + collection.getRole(), CollectionPersister.class, collection.getCollectionPersisterClass());
}
Also used : Collection(org.hibernate.mapping.Collection) Test(org.junit.Test)

Example 69 with Collection

use of org.hibernate.mapping.Collection in project hibernate-orm by hibernate.

the class BaseNonConfigCoreFunctionalTestCase method applyCacheSettings.

protected final void applyCacheSettings(Metadata metadata) {
    if (!overrideCacheStrategy()) {
        return;
    }
    if (getCacheConcurrencyStrategy() == null) {
        return;
    }
    for (PersistentClass entityBinding : metadata.getEntityBindings()) {
        if (entityBinding.isInherited()) {
            continue;
        }
        boolean hasLob = false;
        final Iterator props = entityBinding.getPropertyClosureIterator();
        while (props.hasNext()) {
            final Property prop = (Property) props.next();
            if (prop.getValue().isSimpleValue()) {
                if (isLob(((SimpleValue) prop.getValue()).getTypeName())) {
                    hasLob = true;
                    break;
                }
            }
        }
        if (!hasLob) {
            ((RootClass) entityBinding).setCacheConcurrencyStrategy(getCacheConcurrencyStrategy());
            entityBinding.setCached(true);
        }
    }
    for (Collection collectionBinding : metadata.getCollectionBindings()) {
        boolean isLob = false;
        if (collectionBinding.getElement().isSimpleValue()) {
            isLob = isLob(((SimpleValue) collectionBinding.getElement()).getTypeName());
        }
        if (!isLob) {
            collectionBinding.setCacheConcurrencyStrategy(getCacheConcurrencyStrategy());
        }
    }
}
Also used : RootClass(org.hibernate.mapping.RootClass) Iterator(java.util.Iterator) Collection(org.hibernate.mapping.Collection) Property(org.hibernate.mapping.Property) PersistentClass(org.hibernate.mapping.PersistentClass) SimpleValue(org.hibernate.mapping.SimpleValue)

Example 70 with Collection

use of org.hibernate.mapping.Collection in project hibernate-orm by hibernate.

the class CorrectnessTestCase method buildMetadata.

private Metadata buildMetadata(StandardServiceRegistry registry) {
    MetadataSources metadataSources = new MetadataSources(registry);
    for (Class entityClass : getAnnotatedClasses()) {
        metadataSources.addAnnotatedClass(entityClass);
    }
    Metadata metadata = metadataSources.buildMetadata();
    for (PersistentClass entityBinding : metadata.getEntityBindings()) {
        if (!entityBinding.isInherited()) {
            ((RootClass) entityBinding).setCacheConcurrencyStrategy(accessType.getExternalName());
        }
    }
    // Collections don't have integrated version, these piggyback on parent's owner version (for DB).
    // However, this version number isn't extractable and is not passed to cache methods.
    AccessType collectionAccessType = accessType == AccessType.NONSTRICT_READ_WRITE ? AccessType.READ_WRITE : accessType;
    for (Collection collectionBinding : metadata.getCollectionBindings()) {
        collectionBinding.setCacheConcurrencyStrategy(collectionAccessType.getExternalName());
    }
    return metadata;
}
Also used : RootClass(org.hibernate.mapping.RootClass) MetadataSources(org.hibernate.boot.MetadataSources) Metadata(org.hibernate.boot.Metadata) Collection(org.hibernate.mapping.Collection) PersistentClass(org.hibernate.mapping.PersistentClass) RootClass(org.hibernate.mapping.RootClass) AccessType(org.hibernate.cache.spi.access.AccessType) PersistentClass(org.hibernate.mapping.PersistentClass)

Aggregations

Collection (org.hibernate.mapping.Collection)134 Test (org.junit.jupiter.api.Test)80 Bag (org.hibernate.mapping.Bag)61 IdentifierBag (org.hibernate.mapping.IdentifierBag)61 SimpleValue (org.hibernate.mapping.SimpleValue)28 Table (org.hibernate.mapping.Table)27 Set (org.hibernate.mapping.Set)25 ITable (org.jboss.tools.hibernate.runtime.spi.ITable)24 Test (org.junit.Test)23 PersistentClass (org.hibernate.mapping.PersistentClass)22 ManyToOne (org.hibernate.mapping.ManyToOne)14 KeyValue (org.hibernate.mapping.KeyValue)13 IValue (org.jboss.tools.hibernate.runtime.spi.IValue)12 Property (org.hibernate.mapping.Property)11 Metadata (org.hibernate.boot.Metadata)9 MetadataSources (org.hibernate.boot.MetadataSources)9 Column (org.hibernate.mapping.Column)9 Iterator (java.util.Iterator)7 Component (org.hibernate.mapping.Component)7 AbstractValueFacade (org.jboss.tools.hibernate.runtime.common.AbstractValueFacade)7