public void AddJoinPredicatesForRelatedEntity()

in src/Core/Resolvers/Sql Query Structures/BaseSqlQueryStructure.cs [232:338]


        public void AddJoinPredicatesForRelatedEntity(
            string targetEntityName,
            string relatedSourceAlias,
            BaseSqlQueryStructure subQuery)
        {
            SourceDefinition sourceDefinition = GetUnderlyingSourceDefinition();
            DatabaseObject relatedEntityDbObject = MetadataProvider.EntityToDatabaseObject[targetEntityName];
            SourceDefinition relatedEntitySourceDefinition = MetadataProvider.GetSourceDefinition(targetEntityName);
            if (// Search for the foreign key information either in the source or target entity.
                sourceDefinition.SourceEntityRelationshipMap.TryGetValue(
                    EntityName,
                    out RelationshipMetadata? relationshipMetadata)
                && relationshipMetadata.TargetEntityToFkDefinitionMap.TryGetValue(
                    targetEntityName,
                    out List<ForeignKeyDefinition>? foreignKeyDefinitions)
                || relatedEntitySourceDefinition.SourceEntityRelationshipMap.TryGetValue(
                    targetEntityName, out relationshipMetadata)
                && relationshipMetadata.TargetEntityToFkDefinitionMap.TryGetValue(
                    EntityName,
                    out foreignKeyDefinitions))
            {
                Dictionary<DatabaseObject, string> associativeTableAndAliases = new();
                // For One-One and One-Many, not all fk definitions are valid
                // and at least 1 will be.
                // Identify the side of the relationship first, then check if its valid
                // by ensuring the referencing and referenced column count > 0
                // before adding the predicates.
                foreach (ForeignKeyDefinition foreignKeyDefinition in foreignKeyDefinitions)
                {
                    // First identify which side of the relationship, this fk definition
                    // is looking at.
                    if (foreignKeyDefinition.Pair.ReferencingDbTable.Equals(DatabaseObject))
                    {
                        // Case where fk in parent entity references the nested entity.
                        // Verify this is a valid fk definition before adding the join predicate.
                        if (foreignKeyDefinition.ReferencingColumns.Count > 0
                            && foreignKeyDefinition.ReferencedColumns.Count > 0)
                        {
                            subQuery.Predicates.AddRange(CreateJoinPredicates(
                                SourceAlias,
                                foreignKeyDefinition.ReferencingColumns,
                                relatedSourceAlias,
                                foreignKeyDefinition.ReferencedColumns));
                        }
                    }
                    else if (foreignKeyDefinition.Pair.ReferencingDbTable.Equals(relatedEntityDbObject))
                    {
                        // Case where fk in nested entity references the parent entity.
                        if (foreignKeyDefinition.ReferencingColumns.Count > 0
                            && foreignKeyDefinition.ReferencedColumns.Count > 0)
                        {
                            subQuery.Predicates.AddRange(CreateJoinPredicates(
                                relatedSourceAlias,
                                foreignKeyDefinition.ReferencingColumns,
                                SourceAlias,
                                foreignKeyDefinition.ReferencedColumns));
                        }
                    }
                    else
                    {
                        DatabaseObject associativeTableDbObject =
                            foreignKeyDefinition.Pair.ReferencingDbTable;
                        // Case when the linking object is the referencing table
                        if (!associativeTableAndAliases.TryGetValue(
                                associativeTableDbObject,
                                out string? associativeTableAlias))
                        {
                            // this is the first fk definition found for this associative table.
                            // create an alias for it and store for later lookup.
                            associativeTableAlias = CreateTableAlias();
                            associativeTableAndAliases.Add(associativeTableDbObject, associativeTableAlias);
                        }

                        if (foreignKeyDefinition.Pair.ReferencedDbTable.Equals(DatabaseObject))
                        {
                            subQuery.Predicates.AddRange(CreateJoinPredicates(
                                associativeTableAlias,
                                foreignKeyDefinition.ReferencingColumns,
                                SourceAlias,
                                foreignKeyDefinition.ReferencedColumns));
                        }
                        else
                        {
                            subQuery.Joins.Add(new SqlJoinStructure
                            (
                                associativeTableDbObject,
                                associativeTableAlias,
                                CreateJoinPredicates(
                                    associativeTableAlias,
                                    foreignKeyDefinition.ReferencingColumns,
                                    relatedSourceAlias,
                                    foreignKeyDefinition.ReferencedColumns
                                    ).ToList()
                            ));
                        }
                    }
                }
            }
            else
            {
                throw new DataApiBuilderException(
                message: $"Could not find relationship between entities: {EntityName} and " +
                $"{targetEntityName}.",
                statusCode: HttpStatusCode.BadRequest,
                subStatusCode: DataApiBuilderException.SubStatusCodes.BadRequest);
            }
        }