public FromElementType(FromElement fromElement, IEntityPersister persister, EntityType entityType) { _fromElement = fromElement; _persister = persister; _entityType = entityType; var queryable = persister as IQueryable; if (queryable != null) fromElement.Text = queryable.TableName + " " + fromElement.TableAlias; }
public FromElementType(FromElement fromElement, IEntityPersister persister, EntityType entityType) { _fromElement = fromElement; _persister = persister; _entityType = entityType; if (persister != null) { fromElement.Text = ((IQueryable)persister).TableName + " " + TableAlias; } }
/// <summary> /// Visit a many-to-one or one-to-one associated entity. Default superclass implementation is a no-op. /// </summary> /// <param name="value"></param> /// <param name="entityType"></param> /// <returns></returns> internal override object ProcessEntity(object value, EntityType entityType) { if (value != null) { Session.PersistenceContext.ReassociateIfUninitializedProxy(value); // if it is an initialized proxy, let cascade // handle it later on } return null; }
private void DereferenceEntity(EntityType entityType, bool implicitJoin, string classAlias, bool generateJoin, IASTNode parent) { CheckForCorrelatedSubquery( "dereferenceEntity" ); // three general cases we check here as to whether to render a physical SQL join: // 1) is our parent a DotNode as well? If so, our property reference is // being further de-referenced... // 2) is this a DML statement // 3) we were asked to generate any needed joins (generateJoins==true) *OR* // we are currently processing a select or from clause // (an additional check is the REGRESSION_STYLE_JOIN_SUPPRESSION check solely intended for the test suite) // // The REGRESSION_STYLE_JOIN_SUPPRESSION is an additional check // intended solely for use within the test suite. This forces the // implicit join resolution to behave more like the classic parser. // The underlying issue is that classic translator is simply wrong // about its decisions on whether or not to render an implicit join // into a physical SQL join in a lot of cases. The piece it generally // tends to miss is that INNER joins effect the results by further // restricting the data set! A particular manifestation of this is // the fact that the classic translator will skip the physical join // for ToOne implicit joins *if the query is shallow*; the result // being that Query.list() and Query.iterate() could return // different number of results! DotNode parentAsDotNode = null; string property = _propertyName; bool joinIsNeeded; if ( IsDotNode( parent ) ) { // our parent is another dot node, meaning we are being further dereferenced. // thus we need to generate a join unless the parent refers to the associated // entity's PK (because 'our' table would know the FK). parentAsDotNode = ( DotNode ) parent; property = parentAsDotNode._propertyName; joinIsNeeded = generateJoin && !IsReferenceToPrimaryKey( parentAsDotNode._propertyName, entityType ); } else if ( ! Walker.IsSelectStatement ) { // in non-select queries, the only time we should need to join is if we are in a subquery from clause joinIsNeeded = Walker.CurrentStatementType == HqlSqlWalker.SELECT && Walker.IsInFrom; } else if ( REGRESSION_STYLE_JOIN_SUPPRESSION ) { // this is the regression style determination which matches the logic of the classic translator joinIsNeeded = generateJoin && ( !Walker.IsInSelect || !Walker.IsShallowQuery); } else { joinIsNeeded = generateJoin || ( Walker.IsInSelect || Walker.IsInFrom ); } if ( joinIsNeeded ) { DereferenceEntityJoin( classAlias, entityType, implicitJoin, parent ); } else { DereferenceEntityIdentifier( property, parentAsDotNode ); } }
/// <summary>Add the parent-child relationship for certain propType conditions</summary> private void MaybeAddToGraph(EntityInfo child, EntityInfo parent, EntityType propType) { if (!(propType.IsOneToOne && propType.UseLHSPrimaryKey && (propType.ForeignKeyDirection == ForeignKeyDirection.ForeignKeyToParent))) { AddToGraph(child, parent); } }
/// <summary> /// Set an association value based on the value of the foreign key. This updates the property of the entity. /// </summary> /// <param name="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> /// <param name="propType">Type of the property</param> /// <param name="entityInfo">Breeze EntityInfo</param> /// <param name="meta">Metadata for the entity class</param> private void FixupRelationship(string propName, EntityType propType, EntityInfo entityInfo, IClassMetadata meta) { var entity = entityInfo.Entity; if (removeMode) { meta.SetPropertyValue(entity, propName, null, EntityMode.Poco); return; } object relatedEntity = GetPropertyValue(meta, entity, propName); if (relatedEntity != null) { // entities are already connected - still need to add to dependency graph EntityInfo relatedEntityInfo = FindInSaveMapByEntity(propType.ReturnedClass, relatedEntity); MaybeAddToGraph(entityInfo, relatedEntityInfo, propType); return; } relatedEntity = GetRelatedEntity(propName, propType, entityInfo, meta); if (relatedEntity != null) meta.SetPropertyValue(entity, propName, relatedEntity, EntityMode.Poco); }
/// <summary> /// /// </summary> /// <param name="path"></param> /// <param name="etype"></param> /// <param name="columns"></param> /// <param name="factory"></param> protected void InitIdentifierPropertyPaths( string path, EntityType etype, string[] columns, ISessionFactoryImplementor factory ) { IType idtype = etype.GetIdentifierOrUniqueKeyType( factory ); if ( !etype.IsUniqueKeyReference ) { string idpath1 = ExtendPath( path, PathExpressionParser.EntityID ); AddPropertyPath( idpath1, idtype, columns ); InitPropertyPaths( idpath1, idtype, columns, factory ); } string idPropName = etype.GetIdentifierOrUniqueKeyPropertyName( factory ); if ( idPropName!=null ) { string idpath2 = ExtendPath( path, idPropName ); AddPropertyPath( idpath2, idtype, columns ); InitPropertyPaths( idpath2, idtype, columns, factory ); } }
protected void InitIdentifierPropertyPaths(string path, EntityType etype, string[] columns, IMapping factory) { IType idtype = etype.GetIdentifierOrUniqueKeyType(factory); string idPropName = etype.GetIdentifierOrUniqueKeyPropertyName(factory); bool hasNonIdentifierPropertyNamedId = HasNonIdentifierPropertyNamedId(etype, factory); if (etype.IsReferenceToPrimaryKey) { if (!hasNonIdentifierPropertyNamedId) { string idpath1 = ExtendPath(path, EntityPersister.EntityID); AddPropertyPath(idpath1, idtype, columns, null); InitPropertyPaths(idpath1, idtype, columns, null, factory); } } if (idPropName != null) { string idpath2 = ExtendPath(path, idPropName); AddPropertyPath(idpath2, idtype, columns, null); InitPropertyPaths(idpath2, idtype, columns, null, factory); } }
public EntityMetamodel(PersistentClass persistentClass, ISessionFactoryImplementor sessionFactory) { this.sessionFactory = sessionFactory; name = persistentClass.EntityName; rootName = persistentClass.RootClazz.EntityName; entityType = TypeFactory.ManyToOne(name); type = persistentClass.MappedClass; rootType = persistentClass.RootClazz.MappedClass; rootTypeAssemblyQualifiedName = rootType.AssemblyQualifiedName; identifierProperty = PropertyFactory.BuildIdentifierProperty(persistentClass, sessionFactory.GetIdentifierGenerator(rootType)); versioned = persistentClass.IsVersioned; bool lazyAvailable = persistentClass.HasPocoRepresentation && FieldInterceptionHelper.IsInstrumented(persistentClass.MappedClass); bool hasLazy = false; propertySpan = persistentClass.PropertyClosureSpan; properties = new StandardProperty[propertySpan]; List<int> naturalIdNumbers = new List<int>(); #region temporary propertyNames = new string[propertySpan]; propertyTypes = new IType[propertySpan]; propertyUpdateability = new bool[propertySpan]; propertyInsertability = new bool[propertySpan]; insertInclusions = new ValueInclusion[propertySpan]; updateInclusions = new ValueInclusion[propertySpan]; nonlazyPropertyUpdateability = new bool[propertySpan]; propertyCheckability = new bool[propertySpan]; propertyNullability = new bool[propertySpan]; propertyVersionability = new bool[propertySpan]; propertyLaziness = new bool[propertySpan]; cascadeStyles = new CascadeStyle[propertySpan]; #endregion int i = 0; int tempVersionProperty = NoVersionIndex; bool foundCascade = false; bool foundCollection = false; bool foundMutable = false; bool foundInsertGeneratedValue = false; bool foundUpdateGeneratedValue = false; bool foundNonIdentifierPropertyNamedId = false; foreach (Mapping.Property prop in persistentClass.PropertyClosureIterator) { if (prop == persistentClass.Version) { tempVersionProperty = i; properties[i] = PropertyFactory.BuildVersionProperty(prop, lazyAvailable); } else { properties[i] = PropertyFactory.BuildStandardProperty(prop, lazyAvailable); } if (prop.IsNaturalIdentifier) { naturalIdNumbers.Add(i); } if ("id".Equals(prop.Name)) { foundNonIdentifierPropertyNamedId = true; } #region temporary bool lazyProperty = prop.IsLazy && lazyAvailable; if (lazyProperty) hasLazy = true; propertyLaziness[i] = lazyProperty; propertyNames[i] = properties[i].Name; propertyTypes[i] = properties[i].Type; propertyNullability[i] = properties[i].IsNullable; propertyUpdateability[i] = properties[i].IsUpdateable; propertyInsertability[i] = properties[i].IsInsertable; insertInclusions[i] = DetermineInsertValueGenerationType(prop, properties[i]); updateInclusions[i] = DetermineUpdateValueGenerationType(prop, properties[i]); propertyVersionability[i] = properties[i].IsVersionable; nonlazyPropertyUpdateability[i] = properties[i].IsUpdateable && !lazyProperty; propertyCheckability[i] = propertyUpdateability[i] || (propertyTypes[i].IsAssociationType && ((IAssociationType) propertyTypes[i]).IsAlwaysDirtyChecked); cascadeStyles[i] = properties[i].CascadeStyle; #endregion if (properties[i].IsLazy) { hasLazy = true; } if (properties[i].CascadeStyle != CascadeStyle.None) { foundCascade = true; } if (IndicatesCollection(properties[i].Type)) { foundCollection = true; } if (propertyTypes[i].IsMutable && propertyCheckability[i]) { foundMutable = true; } if (insertInclusions[i] != ValueInclusion.None) { foundInsertGeneratedValue = true; } if (updateInclusions[i] != ValueInclusion.None) { foundUpdateGeneratedValue = true; } MapPropertyToIndex(prop, i); i++; } if (naturalIdNumbers.Count == 0) naturalIdPropertyNumbers = null; else naturalIdPropertyNumbers = naturalIdNumbers.ToArray(); hasCascades = foundCascade; hasInsertGeneratedValues = foundInsertGeneratedValue; hasUpdateGeneratedValues = foundUpdateGeneratedValue; hasNonIdentifierPropertyNamedId = foundNonIdentifierPropertyNamedId; versionPropertyIndex = tempVersionProperty; hasLazyProperties = hasLazy; if (hasLazyProperties) log.Info("lazy property fetching available for: " + name); lazy = persistentClass.IsLazy && (!persistentClass.HasPocoRepresentation || !ReflectHelper.IsFinalClass(persistentClass.ProxyInterface)); mutable = persistentClass.IsMutable; if (!persistentClass.IsAbstract.HasValue) { // legacy behavior (with no abstract attribute specified) isAbstract = persistentClass.HasPocoRepresentation && ReflectHelper.IsAbstractClass(persistentClass.MappedClass); } else { isAbstract = persistentClass.IsAbstract.Value; if (!isAbstract && persistentClass.HasPocoRepresentation && ReflectHelper.IsAbstractClass(persistentClass.MappedClass)) { log.Warn("entity [" + type.FullName + "] is abstract-class/interface explicitly mapped as non-abstract; be sure to supply entity-names"); } } selectBeforeUpdate = persistentClass.SelectBeforeUpdate; dynamicUpdate = persistentClass.DynamicUpdate; dynamicInsert = persistentClass.DynamicInsert; polymorphic = persistentClass.IsPolymorphic; explicitPolymorphism = persistentClass.IsExplicitPolymorphism; inherited = persistentClass.IsInherited; superclass = inherited ? persistentClass.Superclass.EntityName : null; superclassType = inherited ? persistentClass.Superclass.MappedClass : null; hasSubclasses = persistentClass.HasSubclasses; optimisticLockMode = persistentClass.OptimisticLockMode; if (optimisticLockMode > Versioning.OptimisticLock.Version && !dynamicUpdate) { throw new MappingException("optimistic-lock setting requires dynamic-update=\"true\": " + type.FullName); } hasCollections = foundCollection; hasMutableProperties = foundMutable; foreach (Subclass obj in persistentClass.SubclassIterator) { subclassEntityNames.Add(obj.EntityName); } subclassEntityNames.Add(name); tuplizerMapping = new EntityEntityModeToTuplizerMapping(persistentClass, this); }
public void InitializeEntity(FromClause fromClause, string className, IEntityPersister persister, EntityType type, string classAlias, string tableAlias) { DoInitialize(fromClause, tableAlias, className, classAlias, persister, type); _initialized = true; }
public EntityMetamodel(PersistentClass persistentClass, ISessionFactoryImplementor sessionFactory) { this.sessionFactory = sessionFactory; // TODO H3: //name = persistentClass.getEntityName(); //rootName = persistentClass.getRootClass().getEntityName(); //entityType = TypeFactory.manyToOne( name ); type = persistentClass.MappedClass; rootType = persistentClass.RootClazz.MappedClass; rootTypeAssemblyQualifiedName = rootType.AssemblyQualifiedName; entityType = TypeFactory.ManyToOne(type); identifierProperty = PropertyFactory.BuildIdentifierProperty( persistentClass, sessionFactory.GetIdentifierGenerator(rootType) ); versioned = persistentClass.IsVersioned; bool lazyAvailable = false; // TODO H3: //bool lazyAvailable = persistentClass.HasPojoRepresentation && // typeof(InterceptFieldEnabled).isAssignableFrom( persistentClass.getMappedClass() ); bool hasLazy = false; propertySpan = persistentClass.PropertyClosureSpan; properties = new StandardProperty[propertySpan]; //IList naturalIdNumbers = new ArrayList(); // temporary ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ propertyNames = new string[propertySpan]; propertyTypes = new IType[propertySpan]; propertyUpdateability = new bool[propertySpan]; propertyInsertability = new bool[propertySpan]; insertInclusions = new ValueInclusion[propertySpan]; updateInclusions = new ValueInclusion[propertySpan]; nonlazyPropertyUpdateability = new bool[propertySpan]; propertyCheckability = new bool[propertySpan]; propertyNullability = new bool[propertySpan]; propertyVersionability = new bool[propertySpan]; propertyLaziness = new bool[propertySpan]; cascadeStyles = new Cascades.CascadeStyle[propertySpan]; // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ int i = 0; int tempVersionProperty = NoVersionIndex; bool foundCascade = false; bool foundCollection = false; bool foundMutable = false; bool foundInsertGeneratedValue = false; bool foundUpdateGeneratedValue = false; foreach (Mapping.Property prop in persistentClass.PropertyClosureCollection) { if (prop == persistentClass.Version) { tempVersionProperty = i; properties[i] = PropertyFactory.BuildVersionProperty(prop, lazyAvailable); } else { properties[i] = PropertyFactory.BuildStandardProperty(prop, lazyAvailable); } // if ( prop.IsNaturalIdentifier ) // { // naturalIdNumbers.Add( i ); // } // temporary ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // TODO H3: //bool lazy = prop.IsLazy && lazyAvailable; bool lazyProperty = false; if (lazyProperty) hasLazy = true; propertyLaziness[i] = lazyProperty; propertyNames[i] = properties[i].Name; propertyTypes[i] = properties[i].Type; propertyNullability[i] = properties[i].IsNullable; propertyUpdateability[i] = properties[i].IsUpdateable; propertyInsertability[i] = properties[i].IsInsertable; insertInclusions[i] = DetermineInsertValueGenerationType(prop, properties[i]); updateInclusions[i] = DetermineUpdateValueGenerationType(prop, properties[i]); propertyVersionability[i] = properties[i].IsVersionable; nonlazyPropertyUpdateability[i] = properties[i].IsUpdateable && !lazyProperty; propertyCheckability[i] = propertyUpdateability[i] || (propertyTypes[i].IsAssociationType && ((IAssociationType) propertyTypes[i]).IsAlwaysDirtyChecked); cascadeStyles[i] = properties[i].CascadeStyle; // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ if (properties[i].IsLazy) { hasLazy = true; } if (properties[i].CascadeStyle != Cascades.CascadeStyle.StyleNone) { foundCascade = true; } if (IndicatesCollection(properties[i].Type)) { foundCollection = true; } if (propertyTypes[i].IsMutable && propertyCheckability[i]) { foundMutable = true; } if (insertInclusions[i] != ValueInclusion.None) { foundInsertGeneratedValue = true; } if (updateInclusions[i] != ValueInclusion.None) { foundUpdateGeneratedValue = true; } MapPropertyToIndex(prop, i); i++; } // TODO H3: // if( naturalIdNumbers.Count == 0 ) // { // naturalIdPropertyNumbers = null; // } // else // { // naturalIdPropertyNumbers = ArrayHelper.ToIntArray( naturalIdNumbers ); // } hasCascades = foundCascade; hasInsertGeneratedValues = foundInsertGeneratedValue; hasUpdateGeneratedValues = foundUpdateGeneratedValue; versionPropertyIndex = tempVersionProperty; hasLazyProperties = hasLazy; if (hasLazyProperties) log.Info("lazy property fetching available for: " + type.FullName); lazy = persistentClass.IsLazy; // TODO H3: // lazy = persistentClass.IsLazy && ( // // TODO: this disables laziness even in non-pojo entity modes: // !persistentClass.HasPojoRepresentation || // !ReflectHelper.IsFinalClass( persistentClass.ProxyInterface ) // ); mutable = persistentClass.IsMutable; if (persistentClass.IsAbstract == null) { // legacy behavior (with no abstract attribute specified) isAbstract = persistentClass.HasPojoRepresentation && ReflectHelper.IsAbstractClass(persistentClass.MappedClass); } else { isAbstract = (bool) persistentClass.IsAbstract; if (!isAbstract && persistentClass.HasPojoRepresentation && ReflectHelper.IsAbstractClass(persistentClass.MappedClass)) { log.Warn("entity [" + type.FullName + "] is abstract-class/interface explicitly mapped as non-abstract; be sure to supply entity-names"); } } selectBeforeUpdate = persistentClass.SelectBeforeUpdate; dynamicUpdate = persistentClass.DynamicUpdate; dynamicInsert = persistentClass.DynamicInsert; polymorphic = persistentClass.IsPolymorphic; explicitPolymorphism = persistentClass.IsExplicitPolymorphism; inherited = persistentClass.IsInherited; superclassType = inherited ? persistentClass.Superclass.MappedClass : null; hasSubclasses = persistentClass.HasSubclasses; optimisticLockMode = persistentClass.OptimisticLockMode; if (optimisticLockMode > OptimisticLockMode.Version && !dynamicUpdate) { throw new MappingException("optimistic-lock setting requires dynamic-update=\"true\": " + type.FullName); } hasCollections = foundCollection; hasMutableProperties = foundMutable; // TODO H3: tuplizers = TuplizerLookup.create(persistentClass, this); foreach (PersistentClass obj in persistentClass.SubclassCollection) { // TODO H3: subclassEntityNames.Add( obj.EntityName ); subclassTypes.Add(obj.MappedClass); } // TODO H3: subclassEntityNames.Add( name ); subclassTypes.Add(type); }
/// <summary> /// Set an association value based on the value of the foreign key. This updates the property of the entity. /// </summary> /// <param name="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> /// <param name="propType">Type of the property</param> /// <param name="entityInfo">Breeze EntityInfo</param> /// <param name="meta">Metadata for the entity class</param> private void FixupRelationship(string propName, EntityType propType, EntityInfo entityInfo, IClassMetadata meta) { var entity = entityInfo.Entity; if (removeMode) { meta.SetPropertyValue(entity, propName, null, EntityMode.Poco); return; } object relatedEntity = GetPropertyValue(meta, entity, propName); if (relatedEntity != null) return; // entities are already connected relatedEntity = GetRelatedEntity(propName, propType, entityInfo, meta); if (relatedEntity != null) meta.SetPropertyValue(entity, propName, relatedEntity, EntityMode.Poco); }
private FromElement CreateAndAddFromElement( string className, string classAlias, IEntityPersister entityPersister, EntityType type, string tableAlias) { if (!(entityPersister is IJoinable)) { throw new ArgumentException("EntityPersister " + entityPersister + " does not implement Joinable!"); } FromElement element = CreateFromElement(entityPersister); InitializeAndAddFromElement(element, className, classAlias, entityPersister, type, tableAlias); return element; }
private void InitializeAndAddFromElement(FromElement element, string className, string classAlias, IEntityPersister entityPersister, EntityType type, string tableAlias) { if (tableAlias == null) { AliasGenerator aliasGenerator = _fromClause.AliasGenerator; tableAlias = aliasGenerator.CreateName(entityPersister.EntityName); } element.InitializeEntity(_fromClause, className, entityPersister, type, classAlias, tableAlias); }
private FromElement CreateJoin( string entityClass, string tableAlias, JoinSequence joinSequence, EntityType type, bool manyToMany) { // origin, path, implied, columns, classAlias, IEntityPersister entityPersister = _fromClause.SessionFactoryHelper.RequireClassPersister(entityClass); FromElement destination = CreateAndAddFromElement(entityClass, _classAlias, entityPersister, type, tableAlias); return InitializeJoin(_path, destination, joinSequence, Columns, _origin, manyToMany); }
private FromElement CreateManyToMany( string role, string associatedEntityName, string roleAlias, IEntityPersister entityPersister, EntityType type, JoinType joinType) { FromElement elem; SessionFactoryHelperExtensions sfh = _fromClause.SessionFactoryHelper; if (_inElementsFunction /*implied*/ ) { // For implied many-to-many, just add the end join. JoinSequence joinSequence = CreateJoinSequence(roleAlias, joinType); elem = CreateJoin(associatedEntityName, roleAlias, joinSequence, type, true); } else { // For an explicit many-to-many relationship, add a second join from the intermediate // (many-to-many) table to the destination table. Also, make sure that the from element's // idea of the destination is the destination table. string tableAlias = _fromClause.AliasGenerator.CreateName(entityPersister.EntityName); string[] secondJoinColumns = sfh.GetCollectionElementColumns(role, roleAlias); // Add the second join, the one that ends in the destination table. JoinSequence joinSequence = CreateJoinSequence(roleAlias, joinType); joinSequence.AddJoin(sfh.GetElementAssociationType(_collectionType), tableAlias, joinType, secondJoinColumns); elem = CreateJoin(associatedEntityName, tableAlias, joinSequence, type, false); elem.UseFromFragment = true; } return elem; }
public FromElement CreateEntityJoin( string entityClass, string tableAlias, JoinSequence joinSequence, bool fetchFlag, bool inFrom, EntityType type) { FromElement elem = CreateJoin(entityClass, tableAlias, joinSequence, type, false); elem.Fetch = fetchFlag; //if (numberOfTables > 1 && _implied && !elem.UseFromFragment) // NH Different behavior: numberOfTables was removed because an // implicit join is an implicit join even if it not come from a // multi-table entity if (_implied && !elem.UseFromFragment) { if (Log.IsDebugEnabled) { Log.Debug("createEntityJoin() : Implied entity join"); } elem.UseFromFragment = true; } // If this is an implied join in a FROM clause, then use ANSI-style joining, and set the // flag on the FromElement that indicates that it was implied in the FROM clause itself. if (_implied && inFrom) { joinSequence.SetUseThetaStyle(false); elem.UseFromFragment = true; elem.SetImpliedInFromClause(true); } if (elem.Walker.IsSubQuery) { // two conditions where we need to transform this to a theta-join syntax: // 1) 'elem' is the "root from-element" in correlated subqueries // 2) The DotNode.useThetaStyleImplicitJoins has been set to true // and 'elem' represents an implicit join if (elem.FromClause != elem.Origin.FromClause || DotNode.UseThetaStyleImplicitJoins) { // the "root from-element" in correlated subqueries do need this piece elem.Type = HqlSqlWalker.FROM_FRAGMENT; joinSequence.SetUseThetaStyle(true); elem.UseFromFragment = false; } } return elem; }
/// <summary> /// 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. /// </summary> /// <param name="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> /// <param name="propType">Type of the property</param> /// <param name="entityInfo">Breeze EntityInfo</param> /// <param name="meta">Metadata for the entity class</param> /// <returns></returns> private object GetRelatedEntity(string propName, EntityType propType, EntityInfo entityInfo, IClassMetadata meta) { object relatedEntity = null; string foreignKeyName = FindForeignKey(propName, meta); object id = GetForeignKeyValue(entityInfo, meta, foreignKeyName); if (id != null) { EntityInfo relatedEntityInfo = FindInSaveMap(propType.ReturnedClass, id); if (relatedEntityInfo == null) { var state = entityInfo.EntityState; if (state != EntityState.Deleted || !propType.IsNullable) { var relatedEntityName = propType.Name; relatedEntity = session.Load(relatedEntityName, id, LockMode.None); } } else { bool removeReverseRelationship = propType.UseLHSPrimaryKey; AddToGraph(entityInfo, relatedEntityInfo, removeReverseRelationship); relatedEntity = relatedEntityInfo.Entity; } } return relatedEntity; }
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. }
public EntityMetamodel(PersistentClass persistentClass, ISessionFactoryImplementor sessionFactory) { this.sessionFactory = sessionFactory; name = persistentClass.EntityName; rootName = persistentClass.RootClazz.EntityName; entityType = TypeFactory.ManyToOne(name); type = persistentClass.MappedClass; rootType = persistentClass.RootClazz.MappedClass; rootTypeAssemblyQualifiedName = rootType == null ? null : rootType.AssemblyQualifiedName; identifierProperty = PropertyFactory.BuildIdentifierProperty(persistentClass, sessionFactory.GetIdentifierGenerator(rootName)); versioned = persistentClass.IsVersioned; bool lazyAvailable = persistentClass.HasPocoRepresentation && FieldInterceptionHelper.IsInstrumented(persistentClass.MappedClass); bool hasLazy = false; propertySpan = persistentClass.PropertyClosureSpan; properties = new StandardProperty[propertySpan]; List<int> naturalIdNumbers = new List<int>(); propertyNames = new string[propertySpan]; propertyTypes = new IType[propertySpan]; propertyUpdateability = new bool[propertySpan]; propertyInsertability = new bool[propertySpan]; insertInclusions = new ValueInclusion[propertySpan]; updateInclusions = new ValueInclusion[propertySpan]; nonlazyPropertyUpdateability = new bool[propertySpan]; propertyCheckability = new bool[propertySpan]; propertyNullability = new bool[propertySpan]; propertyVersionability = new bool[propertySpan]; propertyLaziness = new bool[propertySpan]; cascadeStyles = new CascadeStyle[propertySpan]; int i = 0; int tempVersionProperty = NoVersionIndex; bool foundCascade = false; bool foundCollection = false; bool foundMutable = false; bool foundInsertGeneratedValue = false; bool foundUpdateGeneratedValue = false; bool foundNonIdentifierPropertyNamedId = false; HasPocoRepresentation = persistentClass.HasPocoRepresentation; // NH: WARNING if we have to disable lazy/unproxy properties we have to do it in the whole process. lazy = persistentClass.IsLazy && (!persistentClass.HasPocoRepresentation || !ReflectHelper.IsFinalClass(persistentClass.ProxyInterface)); lazyAvailable &= lazy; // <== Disable lazy properties if the class is marked with lazy=false bool hadLazyProperties = false; bool hadNoProxyRelations = false; foreach (Mapping.Property prop in persistentClass.PropertyClosureIterator) { if (prop.IsLazy) { hadLazyProperties = true; } if(prop.UnwrapProxy) { hadNoProxyRelations = true; } // NH: A lazy property is a simple property marked with lazy=true bool islazyProperty = prop.IsLazy && lazyAvailable && (!prop.IsEntityRelation || prop.UnwrapProxy); // NH: A Relation (in this case many-to-one or one-to-one) marked as "no-proxy" var isUnwrapProxy = prop.UnwrapProxy && lazyAvailable; if (islazyProperty || isUnwrapProxy) { // NH: verify property proxiability var getter = prop.GetGetter(persistentClass.MappedClass); if (getter.Method == null || getter.Method.IsDefined(typeof(CompilerGeneratedAttribute), false) == false) { log.ErrorFormat("Lazy or no-proxy property {0}.{1} is not an auto property, which may result in uninitialized property access", persistentClass.EntityName, prop.Name); } } if (prop == persistentClass.Version) { tempVersionProperty = i; properties[i] = PropertyFactory.BuildVersionProperty(prop, islazyProperty); } else { properties[i] = PropertyFactory.BuildStandardProperty(prop, islazyProperty); } if (prop.IsNaturalIdentifier) { naturalIdNumbers.Add(i); } if ("id".Equals(prop.Name)) { foundNonIdentifierPropertyNamedId = true; } if (islazyProperty) { hasLazy = true; } if (isUnwrapProxy) { hasUnwrapProxyForProperties = true; } propertyLaziness[i] = islazyProperty; propertyNames[i] = properties[i].Name; propertyTypes[i] = properties[i].Type; propertyNullability[i] = properties[i].IsNullable; propertyUpdateability[i] = properties[i].IsUpdateable; propertyInsertability[i] = properties[i].IsInsertable; insertInclusions[i] = DetermineInsertValueGenerationType(prop, properties[i]); updateInclusions[i] = DetermineUpdateValueGenerationType(prop, properties[i]); propertyVersionability[i] = properties[i].IsVersionable; nonlazyPropertyUpdateability[i] = properties[i].IsUpdateable && !islazyProperty; propertyCheckability[i] = propertyUpdateability[i] || (propertyTypes[i].IsAssociationType && ((IAssociationType) propertyTypes[i]).IsAlwaysDirtyChecked); cascadeStyles[i] = properties[i].CascadeStyle; if (properties[i].IsLazy) { hasLazy = true; } if (properties[i].CascadeStyle != CascadeStyle.None) { foundCascade = true; } if (IndicatesCollection(properties[i].Type)) { foundCollection = true; } if (propertyTypes[i].IsMutable && propertyCheckability[i]) { foundMutable = true; } if (insertInclusions[i] != ValueInclusion.None) { foundInsertGeneratedValue = true; } if (updateInclusions[i] != ValueInclusion.None) { foundUpdateGeneratedValue = true; } MapPropertyToIndex(prop, i); i++; } if (naturalIdNumbers.Count == 0) naturalIdPropertyNumbers = null; else naturalIdPropertyNumbers = naturalIdNumbers.ToArray(); hasCascades = foundCascade; hasInsertGeneratedValues = foundInsertGeneratedValue; hasUpdateGeneratedValues = foundUpdateGeneratedValue; hasNonIdentifierPropertyNamedId = foundNonIdentifierPropertyNamedId; versionPropertyIndex = tempVersionProperty; hasLazyProperties = hasLazy; if(hadLazyProperties && !hasLazy) { log.WarnFormat("Disabled lazy properies fetching for {0} beacuse it does not support lazy at the entity level", name); } if (hasLazy) { log.Info("lazy property fetching available for: " + name); } if(hadNoProxyRelations && !hasUnwrapProxyForProperties) { log.WarnFormat("Disabled ghost properies fetching for {0} beacuse it does not support lazy at the entity level", name); } if (hasUnwrapProxyForProperties) { log.Info("no-proxy property fetching available for: " + name); } mutable = persistentClass.IsMutable; if (!persistentClass.IsAbstract.HasValue) { // legacy behavior (with no abstract attribute specified) isAbstract = persistentClass.HasPocoRepresentation && ReflectHelper.IsAbstractClass(persistentClass.MappedClass); } else { isAbstract = persistentClass.IsAbstract.Value; if (!isAbstract && persistentClass.HasPocoRepresentation && ReflectHelper.IsAbstractClass(persistentClass.MappedClass)) { log.Warn("entity [" + type.FullName + "] is abstract-class/interface explicitly mapped as non-abstract; be sure to supply entity-names"); } } selectBeforeUpdate = persistentClass.SelectBeforeUpdate; dynamicUpdate = persistentClass.DynamicUpdate; dynamicInsert = persistentClass.DynamicInsert; polymorphic = persistentClass.IsPolymorphic; explicitPolymorphism = persistentClass.IsExplicitPolymorphism; inherited = persistentClass.IsInherited; superclass = inherited ? persistentClass.Superclass.EntityName : null; superclassType = inherited ? persistentClass.Superclass.MappedClass : null; hasSubclasses = persistentClass.HasSubclasses; optimisticLockMode = persistentClass.OptimisticLockMode; if (optimisticLockMode > Versioning.OptimisticLock.Version && !dynamicUpdate) { throw new MappingException("optimistic-lock setting requires dynamic-update=\"true\": " + type.FullName); } hasCollections = foundCollection; hasMutableProperties = foundMutable; foreach (Subclass obj in persistentClass.SubclassIterator) { subclassEntityNames.Add(obj.EntityName); } subclassEntityNames.Add(name); tuplizerMapping = new EntityEntityModeToTuplizerMapping(persistentClass, this); }
/// <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; }
private void DoInitialize(FromClause fromClause, string tableAlias, string className, string classAlias, IEntityPersister persister, EntityType type) { if (_initialized) { throw new InvalidOperationException("Already initialized!!"); } _fromClause = fromClause; _tableAlias = tableAlias; _className = className; _classAlias = classAlias; _elementType = new FromElementType(this, persister, type); // Register the FromElement with the FROM clause, now that we have the names and aliases. fromClause.RegisterFromElement(this); if (Log.IsDebugEnabled) { Log.Debug(fromClause + " : " + className + " (" + (classAlias ?? "no alias") + ") -> " + tableAlias); } }
/// <summary> /// Determine the name of the property for the entity encapsulated by the /// given type which represents the id or unique-key. /// </summary> /// <param name="entityType">The type representing the entity.</param> /// <returns>The corresponding property name</returns> public string GetIdentifierOrUniqueKeyPropertyName(EntityType entityType) { try { return entityType.GetIdentifierOrUniqueKeyPropertyName(_sfi); } catch (MappingException me) { throw new QueryException(me); } }
/// <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); } }
/// <summary> /// Visit a many-to-one or one-to-one associated entity. Default superclass implementation is a no-op. /// </summary> /// <param name="value"></param> /// <param name="entityType"></param> /// <returns></returns> internal virtual object ProcessEntity(object value, EntityType entityType) { return null; }
private bool HasNonIdentifierPropertyNamedId(EntityType entityType, IMapping factory) { // NH: Different implementation (removed done "todo" of H3.2.6) return factory.HasNonIdentifierPropertyNamedId(entityType.GetAssociatedEntityName()); }
/// <summary> /// Visit a many-to-one or one-to-one associated entity. Default /// superclass implementation is a no-op. /// </summary> /// <param name="value"></param> /// <param name="entityType"></param> /// <returns></returns> protected virtual object ProcessEntity(object value, EntityType entityType) { return null; }