private bool HasNonIdentifierPropertyNamedId(EntityType entityType, IMapping factory)
		{
			// NH: Different implementation (removed done "todo" of H3.2.6)
			return factory.HasNonIdentifierPropertyNamedId(entityType.GetAssociatedEntityName());
		}
Exemple #2
0
		/// <summary>
		/// Is the given property name a reference to the primary key of the associated
		/// entity construed by the given entity type?
		/// For example, consider a fragment like order.customer.id
		/// (where order is a from-element alias).  Here, we'd have:
		/// propertyName = "id" AND
		/// owningType = ManyToOneType(Customer)
		/// and are being asked to determine whether "customer.id" is a reference
		/// to customer's PK...
		/// </summary>
		/// <param name="propertyName">The name of the property to check.</param>
		/// <param name="owningType">The type represeting the entity "owning" the property</param>
		/// <returns>True if propertyName references the entity's (owningType->associatedEntity) primary key; false otherwise.</returns>
		private bool IsReferenceToPrimaryKey(string propertyName, EntityType owningType)
		{
			IEntityPersister persister = SessionFactoryHelper.Factory.GetEntityPersister(owningType.GetAssociatedEntityName());
			if (persister.EntityMetamodel.HasNonIdentifierPropertyNamedId)
			{
				// only the identifier property field name can be a reference to the associated entity's PK...
				return propertyName == persister.IdentifierPropertyName && owningType.IsReferenceToPrimaryKey;
			}
			
			// here, we have two possibilities:
			// 		1) the property-name matches the explicitly identifier property name
			//		2) the property-name matches the implicit 'id' property name
			if (EntityPersister.EntityID == propertyName)
			{
				// the referenced node text is the special 'id'
				return owningType.IsReferenceToPrimaryKey;
			}
			
			string keyPropertyName = SessionFactoryHelper.GetIdentifierOrUniqueKeyPropertyName(owningType);
			return keyPropertyName != null && keyPropertyName == propertyName && owningType.IsReferenceToPrimaryKey;
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="propertyName"></param>
		/// <param name="propertyType"></param>
		/// <param name="q"></param>
		/// <remarks>NOTE: we avoid joining to the next table if the named property is just the foreign key value</remarks>
		private void DereferenceEntity(string propertyName, EntityType propertyType, QueryTranslator q)
		{
			//if its "id"
			bool isIdShortcut = EntityID.Equals(propertyName) && !propertyType.IsUniqueKeyReference;

			//or its the id property name
			string idPropertyName;
			try
			{
				idPropertyName = propertyType.GetIdentifierOrUniqueKeyPropertyName(q.Factory);
			}
			catch (MappingException me)
			{
				throw new QueryException(me);
			}
			bool isNamedIdPropertyShortcut = idPropertyName != null && idPropertyName.Equals(propertyName);

			if (isIdShortcut || isNamedIdPropertyShortcut)
			{
				// special shortcut for id properties, skip the join!
				// this must only occur at the _end_ of a path expression
				DereferenceProperty(propertyName);
			}
			else
			{
				string entityClass = propertyType.GetAssociatedEntityName();
				string name = q.CreateNameFor(entityClass);
				q.AddType(name, entityClass);
				//String[] keyColNames = memberPersister.getIdentifierColumnNames();
				AddJoin(name, propertyType);
                if (propertyType.IsOneToOne)
                {
                    oneToOneOwnerName = currentName;
                }
                else
                {
                    oneToOneOwnerName = null;
                }
				ownerAssociationType = propertyType;
				currentName = name;
				currentProperty = propertyName;
				q.AddPathAliasAndJoin(path.ToString(0, path.ToString().LastIndexOf(StringHelper.Dot)), name, joinSequence.Copy());
				componentPath.Length = 0;
				currentPropertyMapping = q.GetPersister(entityClass);
			}
		}
Exemple #4
0
		private void DereferenceEntityJoin(string classAlias, EntityType propertyType, bool impliedJoin, IASTNode parent)
		{
			_dereferenceType = DerefEntity;
			if ( Log.IsDebugEnabled ) 
			{
				Log.Debug( "dereferenceEntityJoin() : generating join for " + _propertyName + " in "
						+ FromElement.ClassName + " "
						+ ( ( classAlias == null ) ? "{no alias}" : "(" + classAlias + ")" )
						+ " parent = " + ASTUtil.GetDebugstring( parent )
				);
			}

			// Create a new FROM node for the referenced class.
			string associatedEntityName = propertyType.GetAssociatedEntityName();
			string tableAlias = AliasGenerator.CreateName( associatedEntityName );

			string[] joinColumns = GetColumns();
			string joinPath = Path;

			if ( impliedJoin && Walker.IsInFrom ) 
			{
				_joinType = Walker.ImpliedJoinType;
			}

			FromClause currentFromClause = Walker.CurrentFromClause;
			FromElement elem = currentFromClause.FindJoinByPath( joinPath );

			///////////////////////////////////////////////////////////////////////////////
			//
			// This is the piece which recognizes the condition where an implicit join path
			// resolved earlier in a correlated subquery is now being referenced in the
			// outer query.  For 3.0final, we just let this generate a second join (which
			// is exactly how the old parser handles this).  Eventually we need to add this
			// logic back in and complete the logic in FromClause.promoteJoin; however,
			// FromClause.promoteJoin has its own difficulties (see the comments in
			// FromClause.promoteJoin).
			//
			//		if ( elem == null ) {
			//			// see if this joinPath has been used in a "child" FromClause, and if so
			//			// promote that element to the outer query
			//			FromClause currentNodeOwner = getFromElement().getFromClause();
			//			FromClause currentJoinOwner = currentNodeOwner.locateChildFromClauseWithJoinByPath( joinPath );
			//			if ( currentJoinOwner != null && currentNodeOwner != currentJoinOwner ) {
			//				elem = currentJoinOwner.findJoinByPathLocal( joinPath );
			//				if ( elem != null ) {
			//					currentFromClause.promoteJoin( elem );
			//					// EARLY EXIT!!!
			//					return;
			//				}
			//			}
			//		}
			//
			///////////////////////////////////////////////////////////////////////////////

			bool found = elem != null;
			// even though we might find a pre-existing element by join path, for FromElements originating in a from-clause
			// we should only ever use the found element if the aliases match (null != null here).  Implied joins are
			// always (?) ok to reuse.
			bool useFoundFromElement = found && ( elem.IsImplied || ( AreSame(classAlias, elem.ClassAlias ) ) );

			if ( ! useFoundFromElement )
			{
				// If this is an implied join in a from element, then use the impled join type which is part of the
				// tree parser's state (set by the gramamar actions).
				JoinSequence joinSequence = SessionFactoryHelper
					.CreateJoinSequence( impliedJoin, propertyType, tableAlias, _joinType, joinColumns );

				FromElementFactory factory = new FromElementFactory(
						currentFromClause,
						GetLhs().FromElement,
						joinPath,
						classAlias,
						joinColumns,
						impliedJoin
				);
				elem = factory.CreateEntityJoin(
						associatedEntityName,
						tableAlias,
						joinSequence,
						_fetch,
						Walker.IsInFrom,
						propertyType
				);
			}
			else 
			{
				currentFromClause.AddDuplicateAlias(classAlias, elem);
			}
		

			SetImpliedJoin( elem );
			Walker.AddQuerySpaces( elem.EntityPersister.QuerySpaces );
			FromElement = elem;	// This 'dot' expression now refers to the resulting from element.
		}