/** * Used to detect circularities in the joined graph, note that * this method is side-effecty */ protected boolean isDuplicateAssociation( final String lhsTable, final String[] lhsColumnNames, final AssociationType type ) { final String foreignKeyTable; final String[] foreignKeyColumns; if ( type.getForeignKeyDirection()==ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT ) { foreignKeyTable = lhsTable; foreignKeyColumns = lhsColumnNames; } else { foreignKeyTable = type.getAssociatedJoinable( getFactory() ).getTableName(); foreignKeyColumns = JoinHelper.getRHSColumnNames( type, getFactory() ); } return isDuplicateAssociation(foreignKeyTable, foreignKeyColumns); }
/** * Get a related entity based on the value of the foreign key. Attempts to find the related entity in the * saveMap; if its not found there, it is loaded via the Session (which should create a proxy, not actually load * the entity from the database). * Related entities are Promoted in the saveOrder according to their state. * @param propName Name of the navigation/association property of the entity, e.g. "Customer". May be null if the property is the entity's identifier. * @param propType Type of the property * @param entityInfo Breeze EntityInfo * @param meta Metadata for the entity class * @return */ private Object getRelatedEntity(String propName, EntityType propType, EntityInfo entityInfo, ClassMetadata meta) { Object relatedEntity = null; String foreignKeyName = findForeignKey(propName, meta); Object id = getForeignKeyValue(entityInfo, meta, foreignKeyName); if (id != null) { Class returnEntityClass = propType.getReturnedClass(); EntityInfo relatedEntityInfo = saveWorkState.findEntityInfoById(returnEntityClass, id); if (relatedEntityInfo == null) { EntityState state = entityInfo.entityState; // if (state == EntityState.Added || state == EntityState.Modified || (state == EntityState.Deleted // && propType.getForeignKeyDirection() != ForeignKeyDirection.FOREIGN_KEY_TO_PARENT)) { if (state != EntityState.Deleted || propType.getForeignKeyDirection() != ForeignKeyDirection.FOREIGN_KEY_TO_PARENT) { String relatedEntityName = propType.getName(); relatedEntity = session.load(relatedEntityName, (Serializable) id, LockOptions.NONE); } } else { maybeAddToGraph(entityInfo, relatedEntityInfo, propType); relatedEntity = relatedEntityInfo.entity; } } return relatedEntity; }
/** * Used to detect circularities in the joined graph, note that * this method is side-effecty */ protected boolean isDuplicateAssociation(final String lhsTable, final String[] lhsColumnNames, final AssociationType type) { final String foreignKeyTable; final String[] foreignKeyColumns; if ( type.getForeignKeyDirection()==ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT ) { foreignKeyTable = lhsTable; foreignKeyColumns = lhsColumnNames; } else { foreignKeyTable = type.getAssociatedJoinable( getFactory() ).getTableName(); foreignKeyColumns = JoinHelper.getRHSColumnNames( type, getFactory() ); } return isDuplicateAssociation(foreignKeyTable, foreignKeyColumns); }
@Override public AssociationKey getAssociationKey() { final AssociationType type = getType(); if ( type.isAnyType() ) { return new AssociationKey( JoinHelper.getLHSTableName( type, attributeNumber(), (OuterJoinLoadable) getSource() ), JoinHelper.getLHSColumnNames( type, attributeNumber(), 0, (OuterJoinLoadable) getSource(), sessionFactory() ) ); } final Joinable joinable = type.getAssociatedJoinable( sessionFactory() ); if ( type.getForeignKeyDirection() == ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT ) { final String lhsTableName; final String[] lhsColumnNames; if ( joinable.isCollection() ) { final QueryableCollection collectionPersister = (QueryableCollection) joinable; lhsTableName = collectionPersister.getTableName(); lhsColumnNames = collectionPersister.getElementColumnNames(); } else { final OuterJoinLoadable entityPersister = (OuterJoinLoadable) source(); lhsTableName = getLHSTableName( type, attributeNumber(), entityPersister ); lhsColumnNames = getLHSColumnNames( type, attributeNumber(), entityPersister, sessionFactory() ); } return new AssociationKey( lhsTableName, lhsColumnNames ); } else { return new AssociationKey( joinable.getTableName(), getRHSColumnNames( type, sessionFactory() ) ); } }
protected void entityIsTransient(MergeEvent event, Map copyCache) { LOG.trace( "Merging transient instance" ); final Object entity = event.getEntity(); final EventSource source = event.getSession(); final String entityName = event.getEntityName(); final EntityPersister persister = source.getEntityPersister( entityName, entity ); final Serializable id = persister.hasIdentifierProperty() ? persister.getIdentifier( entity, source ) : null; if ( copyCache.containsKey( entity ) ) { persister.setIdentifier( copyCache.get( entity ), id, source ); } else { ( (MergeContext) copyCache ).put( entity, source.instantiate( persister, id ), true ); //before cascade! } final Object copy = copyCache.get( entity ); // cascade first, so that all unsaved objects get their // copy created before we actually copy //cascadeOnMerge(event, persister, entity, copyCache, Cascades.CASCADE_BEFORE_MERGE); super.cascadeBeforeSave( source, persister, entity, copyCache ); copyValues( persister, entity, copy, source, copyCache, ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT ); saveTransientEntity( copy, entityName, event.getRequestedId(), source, copyCache ); // cascade first, so that all unsaved objects get their // copy created before we actually copy super.cascadeAfterSave( source, persister, entity, copyCache ); copyValues( persister, entity, copy, source, copyCache, ForeignKeyDirection.FOREIGN_KEY_TO_PARENT ); event.setResult( copy ); }
protected void copyValues( final EntityPersister persister, final Object entity, final Object target, final SessionImplementor source, final Map copyCache, final ForeignKeyDirection foreignKeyDirection) { final Object[] copiedValues; if ( foreignKeyDirection == ForeignKeyDirection.FOREIGN_KEY_TO_PARENT ) { // this is the second pass through on a merge op, so here we limit the // replacement to associations types (value types were already replaced // during the first pass) copiedValues = TypeHelper.replaceAssociations( persister.getPropertyValues( entity ), persister.getPropertyValues( target ), persister.getPropertyTypes(), source, target, copyCache, foreignKeyDirection ); } else { copiedValues = TypeHelper.replace( persister.getPropertyValues( entity ), persister.getPropertyValues( target ), persister.getPropertyTypes(), source, target, copyCache, foreignKeyDirection ); } persister.setPropertyValues( target, copiedValues ); }
protected void copyValues( final EntityPersister persister, final Object entity, final Object target, final SessionImplementor source, final Map copyCache, final ForeignKeyDirection foreignKeyDirection) { final Object[] copiedValues; if ( foreignKeyDirection == ForeignKeyDirection.FOREIGN_KEY_TO_PARENT ) { // this is the second pass through on a merge op, so here we limit the // replacement to associations types (value types were already replaced // during the first pass) copiedValues = TypeFactory.replaceAssociations( persister.getPropertyValues( entity, source.getEntityMode() ), persister.getPropertyValues( target, source.getEntityMode() ), persister.getPropertyTypes(), source, target, copyCache, foreignKeyDirection ); } else { copiedValues = TypeFactory.replace( persister.getPropertyValues( entity, source.getEntityMode() ), persister.getPropertyValues( target, source.getEntityMode() ), persister.getPropertyTypes(), source, target, copyCache, foreignKeyDirection ); } persister.setPropertyValues( target, copiedValues, source.getEntityMode() ); }
public static void bindOneToOne(Element node, OneToOne oneToOne, String path, boolean isNullable, Mappings mappings) throws MappingException { bindColumns( node, oneToOne, isNullable, false, null, mappings ); Attribute constrNode = node.attribute( "constrained" ); boolean constrained = constrNode != null && constrNode.getValue().equals( "true" ); oneToOne.setConstrained( constrained ); oneToOne.setForeignKeyType( constrained ? ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT : ForeignKeyDirection.FOREIGN_KEY_TO_PARENT ); initOuterJoinFetchSetting( node, oneToOne ); initLaziness( node, oneToOne, mappings, true ); 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(); } oneToOne.setEmbedded( "true".equals( embed ) ); Attribute fkNode = node.attribute( "foreign-key" ); if ( fkNode != null ) oneToOne.setForeignKeyName( fkNode.getValue() ); Attribute ukName = node.attribute( "property-ref" ); if ( ukName != null ) oneToOne.setReferencedPropertyName( ukName.getValue() ); oneToOne.setReferenceToPrimaryKey( oneToOne.getReferencedPropertyName() == null ); oneToOne.setPropertyName( node.attributeValue( "name" ) ); oneToOne.setReferencedEntityName( getEntityName( node, mappings ) ); String cascade = node.attributeValue( "cascade" ); if ( cascade != null && cascade.indexOf( "delete-orphan" ) >= 0 ) { if ( oneToOne.isConstrained() ) { throw new MappingException( "one-to-one attribute [" + path + "] does not support orphan delete as it is constrained" ); } } }
protected void entityIsTransient(MergeEvent event, Map copyCache) { log.trace("merging transient instance"); final Object entity = event.getEntity(); final EventSource source = event.getSession(); final EntityPersister persister = source.getEntityPersister( event.getEntityName(), entity ); final String entityName = persister.getEntityName(); final Serializable id = persister.hasIdentifierProperty() ? persister.getIdentifier( entity, source.getEntityMode() ) : null; final Object copy = persister.instantiate( id, source.getEntityMode() ); //TODO: should this be Session.instantiate(Persister, ...)? copyCache.put(entity, copy); //before cascade! // cascade first, so that all unsaved objects get their // copy created before we actually copy //cascadeOnMerge(event, persister, entity, copyCache, Cascades.CASCADE_BEFORE_MERGE); super.cascadeBeforeSave(source, persister, entity, copyCache); copyValues(persister, entity, copy, source, copyCache, ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT); //this bit is only *really* absolutely necessary for handling //requestedId, but is also good if we merge multiple object //graphs, since it helps ensure uniqueness final Serializable requestedId = event.getRequestedId(); if (requestedId==null) { saveWithGeneratedId( copy, entityName, copyCache, source, false ); } else { saveWithRequestedId( copy, requestedId, entityName, copyCache, source ); } // cascade first, so that all unsaved objects get their // copy created before we actually copy super.cascadeAfterSave(source, persister, entity, copyCache); copyValues(persister, entity, copy, source, copyCache, ForeignKeyDirection.FOREIGN_KEY_TO_PARENT); event.setResult(copy); }
/** Add the parent-child relationship for certain propType conditions */ private void maybeAddToGraph(EntityInfo child, EntityInfo parent, EntityType propType) { if (!(propType.isOneToOne() && propType.useLHSPrimaryKey() && (propType.getForeignKeyDirection() == ForeignKeyDirection.FOREIGN_KEY_TO_PARENT))) { addToGraph(child, parent); } }
@Override public Object replace(Object original, Object target, SharedSessionContractImplementor session, Object owner, @SuppressWarnings("rawtypes") Map copyCache, ForeignKeyDirection foreignKeyDirection) throws HibernateException { return columnMapper.getHibernateType().replace(original, target, session, owner, copyCache, foreignKeyDirection); }
public static void bindOneToOne(Element node, OneToOne oneToOne, String path, boolean isNullable, Mappings mappings) throws MappingException { bindColumns( node, oneToOne, isNullable, false, null, mappings ); Attribute constrNode = node.attribute( "constrained" ); boolean constrained = constrNode != null && constrNode.getValue().equals( "true" ); oneToOne.setConstrained( constrained ); oneToOne.setForeignKeyType( constrained ? ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT : ForeignKeyDirection.FOREIGN_KEY_TO_PARENT ); initOuterJoinFetchSetting( node, oneToOne ); initLaziness( node, oneToOne, mappings, true ); oneToOne.setEmbedded( "true".equals( node.attributeValue( "embed-xml" ) ) ); Attribute fkNode = node.attribute( "foreign-key" ); if ( fkNode != null ) oneToOne.setForeignKeyName( fkNode.getValue() ); Attribute ukName = node.attribute( "property-ref" ); if ( ukName != null ) oneToOne.setReferencedPropertyName( ukName.getValue() ); oneToOne.setPropertyName( node.attributeValue( "name" ) ); oneToOne.setReferencedEntityName( getEntityName( node, mappings ) ); validateCascade( node, path ); }
/** * Returns the foreignKeyType. * @return AssociationType.ForeignKeyType */ public ForeignKeyDirection getForeignKeyType() { return foreignKeyType; }
/** * Sets the foreignKeyType. * @param foreignKeyType The foreignKeyType to set */ public void setForeignKeyType(ForeignKeyDirection foreignKeyType) { this.foreignKeyType = foreignKeyType; }