/// <summary> /// Generate a sequence of <c>LEFT OUTER JOIN</c> clauses for the given associations. /// </summary> protected JoinFragment MergeOuterJoins(IList <OuterJoinableAssociation> associations) { JoinFragment outerjoin = Dialect.CreateOuterJoinFragment(); OuterJoinableAssociation last = null; foreach (OuterJoinableAssociation oj in associations) { if (last != null && last.IsManyToManyWith(oj)) { oj.AddManyToManyJoin(outerjoin, (IQueryableCollection)last.Joinable); } else { oj.AddJoins(outerjoin); // NH Different behavior : NH1179 and NH1293 // Apply filters in Many-To-One association if (enabledFiltersForManyToOne.Count > 0) { string manyToOneFilterFragment = oj.Joinable.FilterFragment(oj.RHSAlias, enabledFiltersForManyToOne); bool joinClauseDoesNotContainsFilterAlready = outerjoin.ToFromFragmentString.IndexOfCaseInsensitive(manyToOneFilterFragment) == -1; if (joinClauseDoesNotContainsFilterAlready) { outerjoin.AddCondition(manyToOneFilterFragment); } } } last = oj; } return(outerjoin); }
private void InitStatementString(OuterJoinableAssociation rootAssociation, SqlString projection, SqlString condition, SqlString orderBy, SqlString groupBy, SqlString having, LockMode lockMode) { SqlString selectClause = projection; if (selectClause == null) { int joins = CountEntityPersisters(associations); Suffixes = BasicLoader.GenerateSuffixes(joins + 1); var suffix = Suffixes[joins]; selectClause = new SqlString(GetSelectFragment(rootAssociation, suffix, null) + SelectString(associations)); } JoinFragment ojf = MergeOuterJoins(associations); SqlSelectBuilder select = new SqlSelectBuilder(Factory) .SetLockMode(lockMode, alias) .SetSelectClause(selectClause) .SetFromClause(Dialect.AppendLockHint(lockMode, persister.FromTableFragment(alias)) + persister.FromJoinFragment(alias, true, true)) .SetWhereClause(condition) .SetOuterJoins(ojf.ToFromFragmentString, ojf.ToWhereFragmentString + WhereFragment) .SetOrderByClause( projection == null ? OrderBy(associations, orderBy) : orderBy) .SetGroupByClause(groupBy) .SetHavingClause(having); if (Factory.Settings.IsCommentsEnabled) { select.SetComment(Comment); } SqlString = select.ToSqlString(); }
protected void InitProjection(SqlString projectionString, SqlString whereString, SqlString orderByString, SqlString groupByString, SqlString havingString, IDictionary <string, IFilter> enabledFilters, LockMode lockMode, IList <EntityProjection> entityProjections) { AddAssociations(); int countEntities = entityProjections.Count; if (countEntities > 0) { var associations = new OuterJoinableAssociation[countEntities]; var eagerProps = new bool[countEntities]; var suffixes = new string[countEntities]; for (var i = 0; i < countEntities; i++) { var e = entityProjections[i]; associations[i] = CreateAssociation(e.Persister.EntityMetamodel.EntityType, e.TableAlias); if (e.FetchLazyProperties) { eagerProps[i] = true; } suffixes[i] = e.ColumnAliasSuffix; } InitPersisters(associations, lockMode); Suffixes = suffixes; EagerPropertyFetches = eagerProps; } else { Persisters = Array.Empty <ILoadable>(); Suffixes = Array.Empty <string>(); } InitStatementString(null, projectionString, whereString, orderByString, groupByString, havingString, lockMode); }
/// <summary> /// Adds an association and extracts the aliases the association's 'with clause' is dependent on /// </summary> private void AddAssociation(string subalias, OuterJoinableAssociation association) { var dependentAlias = new DependentAlias { Alias = subalias, }; _dependentAliases.Add(dependentAlias); var on = association.On.ToString(); if (!string.IsNullOrEmpty(on)) { var dependencies = new HashSet <string>(StringComparer.OrdinalIgnoreCase); foreach (Match match in aliasRegex.Matches(on)) { string alias = match.Value; if (string.Equals(alias, subalias, StringComparison.OrdinalIgnoreCase)) { continue; } dependencies.Add(alias); } dependentAlias.DependsOn = dependencies.ToArray(); } associations.Add(association); }
/// <summary> /// Generate a select list of columns containing all properties of the entity classes /// </summary> /// <param name="associations"></param> /// <param name="factory"></param> /// <returns></returns> public string SelectString(IList associations, ISessionFactoryImplementor factory) { if (associations.Count == 0) { return(string.Empty); } else { StringBuilder buf = new StringBuilder(associations.Count * 100); buf.Append(StringHelper.CommaSpace); int aliasCount = 0; for (int i = 0; i < associations.Count; i++) { OuterJoinableAssociation join = ( OuterJoinableAssociation )associations[i]; string selectFragment = join.Joinable.SelectFragment( join.Subalias, Suffixes[aliasCount], join.JoinType == JoinType.LeftOuterJoin ).ToString(); buf.Append(selectFragment); if (join.Joinable.ConsumesAlias()) { aliasCount++; } if (i < associations.Count - 1 && !selectFragment.Trim().Equals(string.Empty)) { buf.Append(StringHelper.CommaSpace); } } return(buf.ToString()); } }
private void FillEntityPersisterProperties(int i, OuterJoinableAssociation oj, ILoadable persister) { persisters[i] = persister; aliases[i] = oj.RHSAlias; EagerPropertyFetches[i] = oj.SelectMode == SelectMode.FetchLazyProperties; ChildFetchEntities[i] = oj.SelectMode == SelectMode.ChildFetch; }
/// <summary> /// Adds an association and extracts the aliases the association's 'with clause' is dependent on /// </summary> private void AddAssociation(string subalias, OuterJoinableAssociation association) { subalias = subalias.ToLower(); var dependencies = new List <string>(); var on = association.On.ToString(); if (!String.IsNullOrEmpty(on)) { foreach (Match match in aliasRegex.Matches(on)) { string alias = match.Groups[1].Value; if (alias == subalias) { continue; } dependencies.Add(alias.ToLower()); } } _dependentAliases.Add(new DependentAlias { Alias = subalias, DependsOn = dependencies.ToArray() }); associations.Add(association); }
internal void AddExplicitEntityJoinAssociation( IOuterJoinLoadable persister, string tableAlias, JoinType joinType, string path, string pathAlias) { OuterJoinableAssociation assoc = InitAssociation(new OuterJoinableAssociation( persister.EntityType, string.Empty, Array.Empty <string>(), tableAlias, joinType, GetWithClause(path, pathAlias), Factory, enabledFilters, GetSelectMode(path)) { ForceFilter = true }, path); AddAssociation(assoc); }
/// <summary> /// Add on association (one-to-one, many-to-one, or a collection) to a list /// of associations to be fetched by outerjoin /// </summary> private void AddAssociationToJoinTree(IAssociationType type, string[] aliasedLhsColumns, string alias, string path, int currentDepth, JoinType joinType) { IJoinable joinable = type.GetAssociatedJoinable(Factory); string subalias = GenerateTableAlias(associations.Count + 1, path, joinable); OuterJoinableAssociation assoc = new OuterJoinableAssociation(type, alias, aliasedLhsColumns, subalias, joinType, GetWithClause(path), Factory, enabledFilters); assoc.ValidateJoin(path); AddAssociation(subalias, assoc); int nextDepth = currentDepth + 1; if (!joinable.IsCollection) { IOuterJoinLoadable pjl = joinable as IOuterJoinLoadable; if (pjl != null) { WalkEntityTree(pjl, subalias, path, nextDepth); } } else { IQueryableCollection qc = joinable as IQueryableCollection; if (qc != null) { WalkCollectionTree(qc, subalias, path, nextDepth); } } }
protected int ToOwner(OuterJoinableAssociation oj, int joins, bool dontIgnore) { if (dontIgnore) { return(oj.Owner == -1 ? joins : oj.Owner); //TODO: UGLY AS SIN! } else { return(-1); } }
public bool IsManyToManyWith(OuterJoinableAssociation other) { if (joinable.IsCollection) { IQueryableCollection persister = (IQueryableCollection)joinable; if (persister.IsManyToMany) { return(persister.ElementType == other.JoinableType); } } return(false); }
/// <summary> /// Generate a sequence of <c>LEFT OUTER JOIN</c> clauses for the given associations. /// </summary> protected JoinFragment MergeOuterJoins(IList <OuterJoinableAssociation> associations) { JoinFragment outerjoin = Dialect.CreateOuterJoinFragment(); var sortedAssociations = GetSortedAssociations(associations); OuterJoinableAssociation last = null; foreach (OuterJoinableAssociation oj in sortedAssociations) { if (last != null && last.IsManyToManyWith(oj)) { oj.AddManyToManyJoin(outerjoin, (IQueryableCollection)last.Joinable); } else { // NH Different behavior : NH1179 and NH1293 // Apply filters for entity joins and Many-To-One associations SqlString filter = null; var enabledFiltersForJoin = oj.ForceFilter ? enabledFilters : enabledFiltersForManyToOne; if (oj.ForceFilter || enabledFiltersForJoin.Count > 0) { string manyToOneFilterFragment = oj.Joinable.FilterFragment(oj.RHSAlias, enabledFiltersForJoin); bool joinClauseDoesNotContainsFilterAlready = oj.On?.IndexOfCaseInsensitive(manyToOneFilterFragment) == -1; if (joinClauseDoesNotContainsFilterAlready) { filter = new SqlString(manyToOneFilterFragment); } } if (TableGroupJoinHelper.ProcessAsTableGroupJoin(new[] { oj }, new[] { oj.On, filter }, true, outerjoin, alias => true, factory)) { continue; } oj.AddJoins(outerjoin); // Ensure that the join condition is added to the join, not the where clause. // Adding the condition to the where clause causes left joins to become inner joins. if (SqlStringHelper.IsNotEmpty(filter)) { outerjoin.AddFromFragmentString(filter); } } last = oj; } return(outerjoin); }
/// <summary> /// Generate a select list of columns containing all properties of the entity classes /// </summary> public string SelectString(IList <OuterJoinableAssociation> associations) { if (associations.Count == 0) { return(string.Empty); } else { SqlStringBuilder buf = new SqlStringBuilder(associations.Count * 3); int entityAliasCount = 0; int collectionAliasCount = 0; for (int i = 0; i < associations.Count; i++) { OuterJoinableAssociation join = associations[i]; OuterJoinableAssociation next = (i == associations.Count - 1) ? null : associations[i + 1]; IJoinable joinable = join.Joinable; string entitySuffix = (suffixes == null || entityAliasCount >= suffixes.Length) ? null : suffixes[entityAliasCount]; string collectionSuffix = (collectionSuffixes == null || collectionAliasCount >= collectionSuffixes.Length) ? null : collectionSuffixes[collectionAliasCount]; string selectFragment = joinable.SelectFragment(next == null ? null : next.Joinable, next == null ? null : next.RHSAlias, join.RHSAlias, entitySuffix, collectionSuffix, join.JoinType == JoinType.LeftOuterJoin); if (selectFragment.Trim().Length > 0) { buf.Add(StringHelper.CommaSpace) .Add(selectFragment); } if (joinable.ConsumesEntityAlias()) { entityAliasCount++; } if (joinable.ConsumesCollectionAlias() && join.JoinType == JoinType.LeftOuterJoin) { collectionAliasCount++; } } return(buf.ToSqlString().ToString()); } }
/// <summary> /// Get the order by string required for collection fetching /// </summary> protected SqlString OrderBy(IList <OuterJoinableAssociation> associations) { SqlStringBuilder buf = new SqlStringBuilder(); OuterJoinableAssociation last = null; foreach (OuterJoinableAssociation oj in associations) { if (oj.JoinType == JoinType.LeftOuterJoin) { if (oj.Joinable.IsCollection) { IQueryableCollection queryableCollection = (IQueryableCollection)oj.Joinable; if (queryableCollection.HasOrdering) { string orderByString = queryableCollection.GetSQLOrderByString(oj.RHSAlias); buf.Add(orderByString).Add(StringHelper.CommaSpace); } } else { // it might still need to apply a collection ordering based on a // many-to-many defined order-by... if (last != null && last.Joinable.IsCollection) { IQueryableCollection queryableCollection = (IQueryableCollection)last.Joinable; if (queryableCollection.IsManyToMany && last.IsManyToManyWith(oj)) { if (queryableCollection.HasManyToManyOrdering) { string orderByString = queryableCollection.GetManyToManyOrderByString(oj.RHSAlias); buf.Add(orderByString).Add(StringHelper.CommaSpace); } } } } } last = oj; } if (buf.Count > 0) { buf.RemoveAt(buf.Count - 1); } return(buf.ToSqlString()); }
/// <summary> /// Generate a select list of columns containing all properties of the entity classes /// </summary> public string SelectString(IList <OuterJoinableAssociation> associations) { if (associations.Count == 0) { return(string.Empty); } else { SqlStringBuilder buf = new SqlStringBuilder(associations.Count * 3); int entityAliasCount = 0; int collectionAliasCount = 0; for (int i = 0; i < associations.Count; i++) { OuterJoinableAssociation join = associations[i]; OuterJoinableAssociation next = (i == associations.Count - 1) ? null : associations[i + 1]; IJoinable joinable = join.Joinable; string entitySuffix = (suffixes == null || entityAliasCount >= suffixes.Length) ? null : suffixes[entityAliasCount]; string collectionSuffix = (collectionSuffixes == null || collectionAliasCount >= collectionSuffixes.Length) ? null : collectionSuffixes[collectionAliasCount]; string selectFragment = GetSelectFragment(join, entitySuffix, collectionSuffix, next); if (!string.IsNullOrWhiteSpace(selectFragment)) { buf.Add(StringHelper.CommaSpace) .Add(selectFragment); } if (joinable.ConsumesEntityAlias() && join.SelectMode != SelectMode.JoinOnly) { entityAliasCount++; } if (joinable.ConsumesCollectionAlias() && join.ShouldFetchCollectionPersister()) { collectionAliasCount++; } } return(buf.ToSqlString().ToString()); } }
/// <summary> /// Generate a sequence of <c>LEFT OUTER JOIN</c> clauses for the given associations. /// </summary> protected JoinFragment MergeOuterJoins(IList <OuterJoinableAssociation> associations) { IList <OuterJoinableAssociation> sortedAssociations = new List <OuterJoinableAssociation>(); var indices = GetTopologicalSortOrder(_dependentAliases); for (int index = indices.Length - 1; index >= 0; index--) { sortedAssociations.Add(associations[indices[index]]); } JoinFragment outerjoin = Dialect.CreateOuterJoinFragment(); OuterJoinableAssociation last = null; foreach (OuterJoinableAssociation oj in sortedAssociations) { if (last != null && last.IsManyToManyWith(oj)) { oj.AddManyToManyJoin(outerjoin, (IQueryableCollection)last.Joinable); } else { oj.AddJoins(outerjoin); // NH Different behavior : NH1179 and NH1293 // Apply filters in Many-To-One association if (enabledFiltersForManyToOne.Count > 0) { string manyToOneFilterFragment = oj.Joinable.FilterFragment(oj.RHSAlias, enabledFiltersForManyToOne); bool joinClauseDoesNotContainsFilterAlready = outerjoin.ToFromFragmentString.IndexOfCaseInsensitive(manyToOneFilterFragment) == -1; if (joinClauseDoesNotContainsFilterAlready) { // Ensure that the join condition is added to the join, not the where clause. // Adding the condition to the where clause causes left joins to become inner joins. outerjoin.AddFromFragmentString(new SqlString(manyToOneFilterFragment)); } } } last = oj; } return(outerjoin); }
internal void AddExplicitEntityJoinAssociation( IOuterJoinLoadable persister, string tableAlias, JoinType joinType, SqlString withClause) { OuterJoinableAssociation assoc = new OuterJoinableAssociation( persister.EntityType, string.Empty, Array.Empty <string>(), tableAlias, joinType, withClause, Factory, enabledFilters); AddAssociation(tableAlias, assoc); }
/// <summary> /// Get the position of the join with the given alias in the list of joins, or -1 if not found /// </summary> /// <param name="alias"></param> /// <param name="associations"></param> /// <returns></returns> private static int GetPosition(string alias, IList associations) { int result = 0; for (int i = 0; i < associations.Count; i++) { OuterJoinableAssociation oj = associations[i] as OuterJoinableAssociation; if (oj.Joinable.ConsumesAlias()) { if (oj.Subalias.Equals(alias)) { return(result); } result++; } } return(-1); }
private static HashSet <string> GetDependsOn(OuterJoinableAssociation association) { if (SqlStringHelper.IsEmpty(association.On)) { return(null); } var dependencies = new HashSet <string>(StringComparer.OrdinalIgnoreCase); foreach (Match match in aliasRegex.Matches(association.On.ToString())) { string alias = match.Value; if (string.Equals(alias, association.RHSAlias, StringComparison.OrdinalIgnoreCase)) { continue; } dependencies.Add(alias); } return(dependencies); }
private void InitClassPersisters(IOuterJoinLoadable persister, IList associations) { int joins = associations.Count; lockModeArray = CreateLockModeArray(joins + 1, LockMode.None); classPersisters = new ILoadable[joins + 1]; Owners = new int[joins + 1]; for (int i = 0; i < joins; i++) { OuterJoinableAssociation oj = ( OuterJoinableAssociation )associations[i]; Persisters[i] = (ILoadable)oj.Joinable; Owners[i] = ToOwner(oj, joins, oj.IsOneToOne); } classPersisters[joins] = persister; Owners[joins] = -1; if (ArrayHelper.IsAllNegative(Owners)) { Owners = null; } }
/// <summary> /// Add on association (one-to-one, many-to-one, or a collection) to a list /// of associations to be fetched by outerjoin /// </summary> private void AddAssociationToJoinTree(IAssociationType type, string[] aliasedLhsColumns, string alias, string path, string subPathAlias, int currentDepth, JoinType joinType) { IJoinable joinable = type.GetAssociatedJoinable(Factory); string subalias = GenerateTableAlias(associations.Count + 1, path, subPathAlias, joinable); var qc = joinable.IsCollection ? (IQueryableCollection)joinable : null; var assoc = new OuterJoinableAssociation( type, alias, aliasedLhsColumns, subalias, joinType, //for many-to-many with clause is applied with OuterJoinableAssociation created for entity persister so simply skip it here qc?.IsManyToMany == true ? null : GetWithClause(path, subPathAlias), Factory, enabledFilters, GetSelectMode(path)); assoc.ValidateJoin(path); AddAssociation(assoc); int nextDepth = currentDepth + 1; if (qc == null) { IOuterJoinLoadable pjl = joinable as IOuterJoinLoadable; if (pjl != null) { WalkEntityTree(pjl, subalias, path, nextDepth); } } else { WalkCollectionTree(qc, subalias, path, subPathAlias, nextDepth); } }
protected static string GetSelectFragment(OuterJoinableAssociation join, string entitySuffix, string collectionSuffix, OuterJoinableAssociation next = null) { switch (join.SelectMode) { case SelectMode.Undefined: case SelectMode.Fetch: #pragma warning disable 618 return(join.Joinable.SelectFragment( next?.Joinable, next?.RHSAlias, join.RHSAlias, entitySuffix, collectionSuffix, join.ShouldFetchCollectionPersister())); #pragma warning restore 618 case SelectMode.FetchLazyProperties: return(ReflectHelper.CastOrThrow <ISupportSelectModeJoinable>(join.Joinable, "fetch lazy propertie") .SelectFragment( next?.Joinable, next?.RHSAlias, join.RHSAlias, entitySuffix, collectionSuffix, join.ShouldFetchCollectionPersister(), true)); case SelectMode.ChildFetch: return(ReflectHelper.CastOrThrow <ISupportSelectModeJoinable>(join.Joinable, "child fetch select mode").IdentifierSelectFragment(join.RHSAlias, entitySuffix)); case SelectMode.JoinOnly: return(string.Empty); default: throw new ArgumentOutOfRangeException(nameof(join.SelectMode), $"{join.SelectMode} is unexpected."); } }
public bool IsManyToManyWith(OuterJoinableAssociation other) { if (joinable.IsCollection) { IQueryableCollection persister = (IQueryableCollection) joinable; if (persister.IsManyToMany) { return persister.ElementType == other.JoinableType; } } return false; }
/// <summary> /// Add on association (one-to-one or many-to-one) to a list of associations be fetched by outerjoin (if necessary) /// </summary> /// <param name="type"></param> /// <param name="aliasedForeignKeyColumns"></param> /// <param name="persister"></param> /// <param name="alias"></param> /// <param name="associations"></param> /// <param name="visitedPersisters"></param> /// <param name="path"></param> /// <param name="currentDepth"></param> /// <param name="joinType"></param> /// <param name="factory"></param> private void WalkAssociationTree( IAssociationType type, string[ ] aliasedForeignKeyColumns, IJoinable persister, string alias, IList associations, ISet visitedPersisters, string path, int currentDepth, JoinType joinType, ISessionFactoryImplementor factory ) { IJoinable joinable = type.GetJoinable( factory ); int maxFetchDepth = factory.MaximumFetchDepth; bool enabled = ( joinType == JoinType.InnerJoin ) || ( ( maxFetchDepth <= 0 || currentDepth < maxFetchDepth ) && !visitedPersisters.Contains( joinable ) && ( !joinable.IsCollection || !ContainsCollectionPersister( associations ) ) ); if ( enabled ) { visitedPersisters.Add( persister ); OuterJoinableAssociation assoc = new OuterJoinableAssociation(); associations.Add( assoc ); // After adding to collection!! string subalias = GenerateTableAlias( joinable.Name, associations.Count, path, joinable.IsManyToMany ); assoc.Joinable = joinable; assoc.TableName = joinable.TableName; assoc.PrimaryKeyColumns = type.GetReferencedColumns( factory ); assoc.ForeignKeyColumns = aliasedForeignKeyColumns; assoc.Subalias = subalias; assoc.Owner = GetPosition( alias, associations ); assoc.IsOneToOne = type.IsEntityType && ( (EntityType) type ).IsOneToOne && !( (EntityType) type ).IsUniqueKeyReference; assoc.JoinType = joinType; if ( assoc.ForeignKeyColumns.Length != assoc.PrimaryKeyColumns.Length || assoc.ForeignKeyColumns.Length == 0 ) { throw new MappingException( string.Format( "Invalid join columns for association: {0}", path ) ); } int nextDepth = currentDepth + 1; if ( !joinable.IsCollection ) { if ( joinable is IOuterJoinLoadable ) { WalkClassTree( (IOuterJoinLoadable) joinable, subalias, associations, visitedPersisters, path, nextDepth, factory ); } } else { if ( joinable is IQueryableCollection ) { WalkCollectionTree( (IQueryableCollection) joinable, subalias, associations, visitedPersisters, path, nextDepth, factory ) ; } } } }
protected int ToOwner( OuterJoinableAssociation oj, int joins, bool dontIgnore ) { if ( dontIgnore ) { return oj.Owner == -1 ? joins : oj.Owner; //TODO: UGLY AS SIN! } else { return -1; } }
/// <summary> /// Add on association (one-to-one or many-to-one) to a list of associations be fetched by outerjoin (if necessary) /// </summary> /// <param name="type"></param> /// <param name="aliasedForeignKeyColumns"></param> /// <param name="persister"></param> /// <param name="alias"></param> /// <param name="associations"></param> /// <param name="visitedPersisters"></param> /// <param name="path"></param> /// <param name="currentDepth"></param> /// <param name="joinType"></param> /// <param name="factory"></param> private void WalkAssociationTree( IAssociationType type, string[] aliasedForeignKeyColumns, IJoinable persister, string alias, IList associations, ISet visitedPersisters, string path, int currentDepth, JoinType joinType, ISessionFactoryImplementor factory) { IJoinable joinable = type.GetJoinable(factory); int maxFetchDepth = factory.MaximumFetchDepth; bool enabled = (joinType == JoinType.InnerJoin) || ( (maxFetchDepth <= 0 || currentDepth < maxFetchDepth) && !visitedPersisters.Contains(joinable) && (!joinable.IsCollection || !ContainsCollectionPersister(associations)) ); if (enabled) { visitedPersisters.Add(joinable); OuterJoinableAssociation assoc = new OuterJoinableAssociation(); associations.Add(assoc); // After adding to collection!! string subalias = GenerateTableAlias( joinable.Name, associations.Count, path, joinable.IsManyToMany); assoc.Joinable = joinable; assoc.TableName = joinable.TableName; assoc.PrimaryKeyColumns = type.GetReferencedColumns(factory); assoc.ForeignKeyColumns = aliasedForeignKeyColumns; assoc.Subalias = subalias; assoc.Owner = GetPosition(alias, associations); assoc.IsOneToOne = type.IsEntityType && ((EntityType)type).IsOneToOne && !((EntityType)type).IsUniqueKeyReference; assoc.JoinType = joinType; if (assoc.ForeignKeyColumns.Length != assoc.PrimaryKeyColumns.Length || assoc.ForeignKeyColumns.Length == 0) { throw new MappingException(string.Format("Invalid join columns for association: {0}", path)); } int nextDepth = currentDepth + 1; if (!joinable.IsCollection) { if (joinable is IOuterJoinLoadable) { WalkClassTree((IOuterJoinLoadable)joinable, subalias, associations, visitedPersisters, path, nextDepth, factory); } } else { if (joinable is IQueryableCollection) { WalkCollectionTree((IQueryableCollection)joinable, subalias, associations, visitedPersisters, path, nextDepth, factory); } } } }
/// <summary> /// Add on association (one-to-one, many-to-one, or a collection) to a list /// of associations to be fetched by outerjoin /// </summary> private void AddAssociationToJoinTree(IAssociationType type, string[] aliasedLhsColumns, string alias, string path, int currentDepth, JoinType joinType) { IJoinable joinable = type.GetAssociatedJoinable(Factory); string subalias = GenerateTableAlias(associations.Count + 1, path, joinable); OuterJoinableAssociation assoc = new OuterJoinableAssociation(type, alias, aliasedLhsColumns, subalias, joinType, GetWithClause(path), Factory, enabledFilters); assoc.ValidateJoin(path); AddAssociation(subalias, assoc); int nextDepth = currentDepth + 1; if (!joinable.IsCollection) { IOuterJoinLoadable pjl = joinable as IOuterJoinLoadable; if (pjl != null) WalkEntityTree(pjl, subalias, path, nextDepth); } else { IQueryableCollection qc = joinable as IQueryableCollection; if (qc != null) WalkCollectionTree(qc, subalias, path, nextDepth); } }
internal OuterJoinableAssociation InitAssociation(OuterJoinableAssociation association, string path) { association.EntityFetchLazyProperties = GetEntityFetchLazyProperties(path); return(association); }
protected static string GetSelectFragment(OuterJoinableAssociation join, string entitySuffix, string collectionSuffix, OuterJoinableAssociation next = null) { return(join.GetSelectFragment(entitySuffix, collectionSuffix, next)); }
/// <summary> /// Adds an association /// </summary> private void AddAssociation(OuterJoinableAssociation association) { associations.Add(association); }
internal string GetSelectFragment(string entitySuffix, string collectionSuffix, OuterJoinableAssociation next) { switch (SelectMode) { case SelectMode.Undefined: case SelectMode.Fetch: #pragma warning disable 618 return(Joinable.SelectFragment( next?.Joinable, next?.RHSAlias, RHSAlias, entitySuffix, collectionSuffix, ShouldFetchCollectionPersister())); #pragma warning restore 618 case SelectMode.FetchLazyProperties: #pragma warning disable 618 return(ReflectHelper.CastOrThrow <ISupportSelectModeJoinable>(Joinable, "fetch lazy properties") .SelectFragment( next?.Joinable, next?.RHSAlias, RHSAlias, entitySuffix, collectionSuffix, ShouldFetchCollectionPersister(), true)); #pragma warning restore 618 case SelectMode.FetchLazyPropertyGroup: return(ReflectHelper.CastOrThrow <ISupportLazyPropsJoinable>(Joinable, "fetch lazy property") .SelectFragment( next?.Joinable, next?.RHSAlias, RHSAlias, collectionSuffix, ShouldFetchCollectionPersister(), new EntityLoadInfo(entitySuffix) { LazyProperties = EntityFetchLazyProperties, IncludeLazyProps = SelectMode == SelectMode.FetchLazyProperties, })); case SelectMode.ChildFetch: return(ReflectHelper.CastOrThrow <ISupportSelectModeJoinable>(Joinable, "child fetch select mode") .IdentifierSelectFragment(RHSAlias, entitySuffix)); case SelectMode.JoinOnly: return(string.Empty); default: throw new ArgumentOutOfRangeException(nameof(SelectMode), $"{SelectMode} is unexpected."); } }
/// <summary> /// Adds an association and extracts the aliases the association's 'with clause' is dependent on /// </summary> private void AddAssociation(string subalias, OuterJoinableAssociation association) { subalias = subalias.ToLower(); var dependencies = new List<string>(); var on = association.On.ToString(); if (!String.IsNullOrEmpty(on)) { foreach (Match match in aliasRegex.Matches(on)) { string alias = match.Groups[1].Value; if (alias == subalias) continue; dependencies.Add(alias.ToLower()); } } _dependentAliases.Add(new DependentAlias { Alias = subalias, DependsOn = dependencies.ToArray() }); associations.Add(association); }
/// <summary> /// Add on association (one-to-one, many-to-one, or a collection) to a list /// of associations to be fetched by outerjoin /// </summary> private void AddAssociationToJoinTree( IAssociationType type, string[] aliasedLhsColumns, string alias, string path, int currentDepth, JoinType joinType) { IJoinable joinable = type.GetAssociatedJoinable(Factory); string subalias = GenerateTableAlias( associations.Count + 1, //before adding to collection! path, joinable ); OuterJoinableAssociation assoc = new OuterJoinableAssociation( type, alias, aliasedLhsColumns, subalias, joinType, Factory, enabledFilters ); assoc.ValidateJoin(path); associations.Add(assoc); int nextDepth = currentDepth + 1; if (!joinable.IsCollection) { if (joinable is IOuterJoinLoadable) { WalkEntityTree( (IOuterJoinLoadable) joinable, subalias, path, nextDepth ); } } else { if (joinable is IQueryableCollection) { WalkCollectionTree( (IQueryableCollection) joinable, subalias, path, nextDepth ); } } }