public void doSecondPass(java.util.Map persistentClasses) throws MappingException { if ( value instanceof ManyToOne ) { ManyToOne manyToOne = (ManyToOne) value; PersistentClass ref = (PersistentClass) persistentClasses.get( manyToOne.getReferencedEntityName() ); if ( ref == null ) { throw new AnnotationException( "@OneToOne or @ManyToOne on " + StringHelper.qualify( entityClassName, path ) + " references an unknown entity: " + manyToOne.getReferencedEntityName() ); } BinderHelper.createSyntheticPropertyReference( columns, ref, null, manyToOne, false, mappings ); TableBinder.bindFk( ref, null, columns, manyToOne, unique, mappings ); /* * HbmMetadataSourceProcessorImpl does this only when property-ref != null, but IMO, it makes sense event if it is null */ if ( !manyToOne.isIgnoreNotFound() ) manyToOne.createPropertyRefConstraints( persistentClasses ); } else if ( value instanceof OneToOne ) { value.createForeignKey(); } else { throw new AssertionFailure( "FkSecondPass for a wrong value type: " + value.getClass().getName() ); } }
/** * @param property The property to bind * @param manyToOne The inverse side */ protected void bindUnidirectionalOneToManyInverseValues(ToMany property, ManyToOne manyToOne) { PropertyConfig config = getPropertyConfig(property); if (config == null) { manyToOne.setLazy(true); } else { manyToOne.setIgnoreNotFound(config.getIgnoreNotFound()); final FetchMode fetch = config.getFetchMode(); if(!fetch.equals(FetchMode.JOIN) && !fetch.equals(FetchMode.EAGER)) { manyToOne.setLazy(true); } final Boolean lazy = config.getLazy(); if(lazy != null) { manyToOne.setLazy(lazy); } } // set referenced entity manyToOne.setReferencedEntityName(property.getAssociatedEntity().getName()); }
/** * Binds a unidirectional one-to-many creating a psuedo back reference property in the process. * * @param property * @param mappings * @param collection */ protected void bindUnidirectionalOneToMany(org.grails.datastore.mapping.model.types.OneToMany property, InFlightMetadataCollector mappings, Collection collection) { Value v = collection.getElement(); v.createForeignKey(); String entityName; if (v instanceof ManyToOne) { ManyToOne manyToOne = (ManyToOne) v; entityName = manyToOne.getReferencedEntityName(); } else { entityName = ((OneToMany) v).getReferencedEntityName(); } collection.setInverse(false); PersistentClass referenced = mappings.getEntityBinding(entityName); Backref prop = new Backref(); PersistentEntity owner = property.getOwner(); prop.setEntityName(owner.getName()); prop.setName(UNDERSCORE + addUnderscore(owner.getJavaClass().getSimpleName(), property.getName()) + "Backref"); prop.setUpdateable(false); prop.setInsertable(true); prop.setCollectionRole(collection.getRole()); prop.setValue(collection.getKey()); prop.setOptional(true); referenced.addProperty(prop); }
/** */ protected void bindManyToOneValues(org.grails.datastore.mapping.model.types.Association property, ManyToOne manyToOne) { PropertyConfig config = getPropertyConfig(property); if (config != null && config.getFetchMode() != null) { manyToOne.setFetchMode(config.getFetchMode()); } else { manyToOne.setFetchMode(FetchMode.DEFAULT); } manyToOne.setLazy(getLaziness(property)); if (config != null) { manyToOne.setIgnoreNotFound(config.getIgnoreNotFound()); } // set referenced entity manyToOne.setReferencedEntityName(property.getAssociatedEntity().getName()); }
public void testProperCallbacks() { ValueVisitor vv = new ValueVisitorValidator(); new Any(new Table()).accept(vv); new Array(new RootClass()).accept(vv); new Bag(new RootClass()).accept(vv); new Component(new RootClass()).accept(vv); new DependantValue(null,null).accept(vv); new IdentifierBag(null).accept(vv); new List(null).accept(vv); new ManyToOne(null).accept(vv); new Map(null).accept(vv); new OneToMany(null).accept(vv); new OneToOne(null, new RootClass() ).accept(vv); new PrimitiveArray(null).accept(vv); new Set(null).accept(vv); new SimpleValue().accept(vv); }
protected boolean isBidirectionalManyToOneWithListMapping(PersistentProperty grailsProperty, Property prop) { if(grailsProperty instanceof Association) { Association association = (Association) grailsProperty; Association otherSide = association.getInverseSide(); return association.isBidirectional() && otherSide != null && prop.getValue() instanceof ManyToOne && List.class.isAssignableFrom(otherSide.getType()); } return false; }
protected String getAssociationDescription(Association grailsProperty) { String assType = "unknown"; if (grailsProperty instanceof ManyToMany) { assType = "many-to-many"; } else if (grailsProperty instanceof org.grails.datastore.mapping.model.types.OneToMany) { assType = "one-to-many"; } else if (grailsProperty instanceof org.grails.datastore.mapping.model.types.OneToOne) { assType = "one-to-one"; } else if (grailsProperty instanceof org.grails.datastore.mapping.model.types.ManyToOne) { assType = "many-to-one"; } else if (grailsProperty.isEmbedded()) { assType = "embedded"; } return assType; }
public static void bindManyToOne(Element node, ManyToOne manyToOne, String path, boolean isNullable, Mappings mappings) throws MappingException { bindColumnsOrFormula( node, manyToOne, path, isNullable, mappings ); initOuterJoinFetchSetting( node, manyToOne ); initLaziness( node, manyToOne, mappings, true ); Attribute ukName = node.attribute( "property-ref" ); if ( ukName != null ) { manyToOne.setReferencedPropertyName( ukName.getValue() ); } manyToOne.setReferencedEntityName( getEntityName( node, mappings ) ); String embed = node.attributeValue( "embed-xml" ); manyToOne.setEmbedded( embed == null || "true".equals( embed ) ); String notFound = node.attributeValue( "not-found" ); manyToOne.setIgnoreNotFound( "ignore".equals( notFound ) ); if( ukName != null && !manyToOne.isIgnoreNotFound() ) { if ( !node.getName().equals("many-to-many") ) { //TODO: really bad, evil hack to fix!!! mappings.addSecondPass( new ManyToOneSecondPass(manyToOne) ); } } Attribute fkNode = node.attribute( "foreign-key" ); if ( fkNode != null ) manyToOne.setForeignKeyName( fkNode.getValue() ); validateCascade( node, path ); }
public static void bindManyToOne(Element node, ManyToOne manyToOne, String path, boolean isNullable, Mappings mappings) throws MappingException { bindColumnsOrFormula( node, manyToOne, path, isNullable, mappings ); initOuterJoinFetchSetting( node, manyToOne ); initLaziness( node, manyToOne, mappings, true ); Attribute ukName = node.attribute( "property-ref" ); if ( ukName != null ) { manyToOne.setReferencedPropertyName( ukName.getValue() ); } manyToOne.setReferenceToPrimaryKey( manyToOne.getReferencedPropertyName() == null ); manyToOne.setReferencedEntityName( getEntityName( node, mappings ) ); String embed = node.attributeValue( "embed-xml" ); // sometimes embed is set to the default value when not specified in the mapping, // so can't seem to determine if an attribute was explicitly set; // log a warning if embed has a value different from the default. if ( !StringHelper.isEmpty( embed ) && !"true".equals( embed ) ) { LOG.embedXmlAttributesNoLongerSupported(); } manyToOne.setEmbedded( embed == null || "true".equals( embed ) ); String notFound = node.attributeValue( "not-found" ); manyToOne.setIgnoreNotFound( "ignore".equals( notFound ) ); if( ukName != null && !manyToOne.isIgnoreNotFound() ) { if ( !node.getName().equals("many-to-many") ) { //TODO: really bad, evil hack to fix!!! mappings.addSecondPass( new ManyToOneSecondPass(manyToOne) ); } } Attribute fkNode = node.attribute( "foreign-key" ); if ( fkNode != null ) manyToOne.setForeignKeyName( fkNode.getValue() ); String cascade = node.attributeValue( "cascade" ); if ( cascade != null && cascade.indexOf( "delete-orphan" ) >= 0 ) { if ( !manyToOne.isLogicalOneToOne() ) { throw new MappingException( "many-to-one attribute [" + path + "] does not support orphan delete as it is not unique" ); } } }
ManyToOneSecondPass(ManyToOne manyToOne) { this.manyToOne = manyToOne; }
/** * bind the inverse FK of a ManyToMany * If we are in a mappedBy case, read the columns from the associated * collection element * Otherwise delegates to the usual algorithm */ public static void bindManytoManyInverseFk( PersistentClass referencedEntity, Ejb3JoinColumn[] columns, SimpleValue value, boolean unique, Mappings mappings) { final String mappedBy = columns[0].getMappedBy(); if ( StringHelper.isNotEmpty( mappedBy ) ) { final Property property = referencedEntity.getRecursiveProperty( mappedBy ); Iterator mappedByColumns; if ( property.getValue() instanceof Collection ) { mappedByColumns = ( (Collection) property.getValue() ).getKey().getColumnIterator(); } else { //find the appropriate reference key, can be in a join Iterator joinsIt = referencedEntity.getJoinIterator(); KeyValue key = null; while ( joinsIt.hasNext() ) { Join join = (Join) joinsIt.next(); if ( join.containsProperty( property ) ) { key = join.getKey(); break; } } if ( key == null ) key = property.getPersistentClass().getIdentifier(); mappedByColumns = key.getColumnIterator(); } while ( mappedByColumns.hasNext() ) { Column column = (Column) mappedByColumns.next(); columns[0].linkValueUsingAColumnCopy( column, value ); } String referencedPropertyName = mappings.getPropertyReferencedAssociation( "inverse__" + referencedEntity.getEntityName(), mappedBy ); if ( referencedPropertyName != null ) { //TODO always a many to one? ( (ManyToOne) value ).setReferencedPropertyName( referencedPropertyName ); mappings.addUniquePropertyReference( referencedEntity.getEntityName(), referencedPropertyName ); } ( (ManyToOne) value ).setReferenceToPrimaryKey( referencedPropertyName == null ); value.createForeignKey(); } else { BinderHelper.createSyntheticPropertyReference( columns, referencedEntity, null, value, true, mappings ); TableBinder.bindFk( referencedEntity, null, columns, value, unique, mappings ); } }
protected void bindListSecondPass(ToMany property, InFlightMetadataCollector mappings, Map<?, ?> persistentClasses, org.hibernate.mapping.List list, String sessionFactoryBeanName) { bindCollectionSecondPass(property, mappings, persistentClasses, list, sessionFactoryBeanName); String columnName = getIndexColumnName(property, sessionFactoryBeanName); final boolean isManyToMany = property instanceof ManyToMany; if (isManyToMany && !property.isOwningSide()) { throw new MappingException("Invalid association [" + property + "]. List collection types only supported on the owning side of a many-to-many relationship."); } Table collectionTable = list.getCollectionTable(); SimpleValue iv = new SimpleValue(mappings, collectionTable); bindSimpleValue("integer", iv, true, columnName, mappings); iv.setTypeName("integer"); list.setIndex(iv); list.setBaseIndex(0); list.setInverse(false); Value v = list.getElement(); v.createForeignKey(); if (property.isBidirectional()) { String entityName; Value element = list.getElement(); if (element instanceof ManyToOne) { ManyToOne manyToOne = (ManyToOne) element; entityName = manyToOne.getReferencedEntityName(); } else { entityName = ((OneToMany) element).getReferencedEntityName(); } PersistentClass referenced = mappings.getEntityBinding(entityName); Class<?> mappedClass = referenced.getMappedClass(); Mapping m = getMapping(mappedClass); boolean compositeIdProperty = isCompositeIdProperty(m, property.getInverseSide()); if (!compositeIdProperty) { Backref prop = new Backref(); final PersistentEntity owner = property.getOwner(); prop.setEntityName(owner.getName()); prop.setName(UNDERSCORE + addUnderscore(owner.getJavaClass().getSimpleName(), property.getName()) + "Backref"); prop.setSelectable(false); prop.setUpdateable(false); if (isManyToMany) { prop.setInsertable(false); } prop.setCollectionRole(list.getRole()); prop.setValue(list.getKey()); DependantValue value = (DependantValue) prop.getValue(); if (!property.isCircular()) { value.setNullable(false); } value.setUpdateable(true); prop.setOptional(false); referenced.addProperty(prop); } if ((!list.getKey().isNullable() && !list.isInverse()) || compositeIdProperty) { IndexBackref ib = new IndexBackref(); ib.setName(UNDERSCORE + property.getName() + "IndexBackref"); ib.setUpdateable(false); ib.setSelectable(false); if (isManyToMany) { ib.setInsertable(false); } ib.setCollectionRole(list.getRole()); ib.setEntityName(list.getOwner().getEntityName()); ib.setValue(list.getIndex()); referenced.addProperty(ib); } } }
protected boolean isBidirectionalManyToOne(PersistentProperty currentGrailsProp) { return ((currentGrailsProp instanceof org.grails.datastore.mapping.model.types.ManyToOne) && ((Association)currentGrailsProp).isBidirectional()); }
/** * Binds a many-to-one relationship to the * */ @SuppressWarnings("unchecked") protected void bindManyToOne(Association property, ManyToOne manyToOne, String path, InFlightMetadataCollector mappings, String sessionFactoryBeanName) { NamingStrategy namingStrategy = getNamingStrategy(sessionFactoryBeanName); bindManyToOneValues(property, manyToOne); PersistentEntity refDomainClass = property instanceof ManyToMany ? property.getOwner() : property.getAssociatedEntity(); Mapping mapping = getMapping(refDomainClass); boolean isComposite = hasCompositeIdentifier(mapping); if (isComposite) { CompositeIdentity ci = (CompositeIdentity) mapping.getIdentity(); bindCompositeIdentifierToManyToOne(property, manyToOne, ci, refDomainClass, path, sessionFactoryBeanName); } else { if (property.isCircular() && (property instanceof ManyToMany)) { PropertyConfig pc = getPropertyConfig(property); if (pc.getColumns().isEmpty()) { mapping.getColumns().put(property.getName(), pc); } if (!hasJoinKeyMapping(pc) ) { JoinTable jt = new JoinTable(); final ColumnConfig columnConfig = new ColumnConfig(); columnConfig.setName(namingStrategy.propertyToColumnName(property.getName()) + UNDERSCORE + FOREIGN_KEY_SUFFIX); jt.setKey(columnConfig); pc.setJoinTable(jt); } bindSimpleValue(property, manyToOne, path, pc, sessionFactoryBeanName); } else { // bind column bindSimpleValue(property, null, manyToOne, path, mappings, sessionFactoryBeanName); } } PropertyConfig config = getPropertyConfig(property); if ((property instanceof org.grails.datastore.mapping.model.types.OneToOne) && !isComposite) { manyToOne.setAlternateUniqueKey(true); Column c = getColumnForSimpleValue(manyToOne); if (config != null && !config.isUniqueWithinGroup()) { c.setUnique(config.isUnique()); } else if (property.isBidirectional() && isHasOne(property.getInverseSide())) { c.setUnique(true); } } }
protected void setCascadeBehaviour(PersistentProperty grailsProperty, Property prop) { String cascadeStrategy = "none"; // set to cascade all for the moment PersistentEntity domainClass = grailsProperty.getOwner(); PropertyConfig config = getPropertyConfig(grailsProperty); if (config != null && config.getCascade() != null) { cascadeStrategy = config.getCascade(); } else if (grailsProperty instanceof Association) { Association association = (Association) grailsProperty; PersistentEntity referenced = association.getAssociatedEntity(); if (isHasOne(association)) { cascadeStrategy = CASCADE_ALL; } else if (association instanceof org.grails.datastore.mapping.model.types.OneToOne) { if (referenced != null && association.isOwningSide()) { cascadeStrategy = CASCADE_ALL; } else { cascadeStrategy = CASCADE_SAVE_UPDATE; } } else if (association instanceof org.grails.datastore.mapping.model.types.OneToMany) { if (referenced != null && association.isOwningSide()) { cascadeStrategy = CASCADE_ALL; } else { cascadeStrategy = CASCADE_SAVE_UPDATE; } } else if (grailsProperty instanceof ManyToMany) { if ((referenced != null && referenced.isOwningEntity(domainClass)) || association.isCircular()) { cascadeStrategy = CASCADE_SAVE_UPDATE; } } else if (grailsProperty instanceof org.grails.datastore.mapping.model.types.ManyToOne) { if (referenced != null && referenced.isOwningEntity(domainClass) && !isCircularAssociation(grailsProperty)) { cascadeStrategy = CASCADE_ALL; } else if(isCompositeIdProperty((Mapping) domainClass.getMapping().getMappedForm(), grailsProperty)) { cascadeStrategy = CASCADE_ALL; } else { cascadeStrategy = CASCADE_NONE; } } else if (grailsProperty instanceof Basic) { cascadeStrategy = CASCADE_ALL; } else if (Map.class.isAssignableFrom(grailsProperty.getType())) { referenced = association.getAssociatedEntity(); if (referenced != null && referenced.isOwningEntity(domainClass)) { cascadeStrategy = CASCADE_ALL; } else { cascadeStrategy = CASCADE_SAVE_UPDATE; } } logCascadeMapping(association, cascadeStrategy, referenced); } prop.setCascade(cascadeStrategy); }
public Object accept(ManyToOne mto) { return validate(ManyToOne.class, mto); }
/** * Binds a many-to-many relationship. A many-to-many consists of * - a key (a DependentValue) * - an element * * The element is a ManyToOne from the association table to the target entity * * @param property The grails property * @param element The ManyToOne element * @param mappings The mappings */ protected void bindManyToMany(Association property, ManyToOne element, InFlightMetadataCollector mappings, String sessionFactoryBeanName) { bindManyToOne(property, element, EMPTY_PATH, mappings, sessionFactoryBeanName); element.setReferencedEntityName(property.getOwner().getName()); }