private void AddReferencingFieldDirective()

in src/Core/Services/GraphQLSchemaCreator.cs [356:438]


        private void AddReferencingFieldDirective(RuntimeEntities entities, Dictionary<string, ObjectTypeDefinitionNode> objectTypes)
        {
            foreach ((string sourceEntityName, ObjectTypeDefinitionNode sourceObjectTypeDefinitionNode) in objectTypes)
            {
                if (!entities.TryGetValue(sourceEntityName, out Entity? entity))
                {
                    continue;
                }

                if (!entity.GraphQL.Enabled || entity.Source.Type is not EntitySourceType.Table || entity.Relationships is null)
                {
                    // Multiple create is only supported on database tables for which GraphQL endpoint is enabled.
                    continue;
                }

                string dataSourceName = _runtimeConfigProvider.GetConfig().GetDataSourceNameFromEntityName(sourceEntityName);
                ISqlMetadataProvider sqlMetadataProvider = _metadataProviderFactory.GetMetadataProvider(dataSourceName);
                SourceDefinition sourceDefinition = sqlMetadataProvider.GetSourceDefinition(sourceEntityName);
                Dictionary<string, FieldDefinitionNode> sourceFieldDefinitions = sourceObjectTypeDefinitionNode.Fields.ToDictionary(field => field.Name.Value, field => field);

                // Retrieve all the relationship information for the source entity which is backed by this table definition.
                sourceDefinition.SourceEntityRelationshipMap.TryGetValue(sourceEntityName, out RelationshipMetadata? relationshipInfo);

                // Retrieve the database object definition for the source entity.
                sqlMetadataProvider.GetEntityNamesAndDbObjects().TryGetValue(sourceEntityName, out DatabaseObject? sourceDbo);
                foreach ((_, EntityRelationship relationship) in entity.Relationships)
                {
                    string targetEntityName = relationship.TargetEntity;
                    if (!string.IsNullOrEmpty(relationship.LinkingObject))
                    {
                        // The presence of LinkingObject indicates that the relationship is a M:N relationship. For M:N relationships,
                        // the fields in this entity are referenced fields and the fields in the linking table are referencing fields.
                        // Thus, it is not required to add the directive to any field in this entity.
                        continue;
                    }

                    // From the relationship information, obtain the foreign key definition for the given target entity and add the
                    // referencing field directive to the referencing fields from the referencing table (whether it is the source entity or the target entity).
                    if (relationshipInfo is not null &&
                        relationshipInfo.TargetEntityToFkDefinitionMap.TryGetValue(targetEntityName, out List<ForeignKeyDefinition>? listOfForeignKeys))
                    {
                        // Find the foreignkeys in which the source entity is the referencing object.
                        IEnumerable<ForeignKeyDefinition> sourceReferencingForeignKeysInfo =
                            listOfForeignKeys.Where(fk =>
                                fk.ReferencingColumns.Count > 0
                                && fk.ReferencedColumns.Count > 0
                                && fk.Pair.ReferencingDbTable.Equals(sourceDbo));

                        sqlMetadataProvider.GetEntityNamesAndDbObjects().TryGetValue(targetEntityName, out DatabaseObject? targetDbo);
                        // Find the foreignkeys in which the target entity is the referencing object, i.e. source entity is the referenced object.
                        IEnumerable<ForeignKeyDefinition> targetReferencingForeignKeysInfo =
                            listOfForeignKeys.Where(fk =>
                                fk.ReferencingColumns.Count > 0
                                && fk.ReferencedColumns.Count > 0
                                && fk.Pair.ReferencingDbTable.Equals(targetDbo));

                        ForeignKeyDefinition? sourceReferencingFKInfo = sourceReferencingForeignKeysInfo.FirstOrDefault();
                        if (sourceReferencingFKInfo is not null)
                        {
                            // When source entity is the referencing entity, referencing field directive is to be added to relationship fields
                            // in the source entity.
                            AddReferencingFieldDirectiveToReferencingFields(sourceFieldDefinitions, sourceReferencingFKInfo.ReferencingColumns, sqlMetadataProvider, sourceEntityName);
                        }

                        ForeignKeyDefinition? targetReferencingFKInfo = targetReferencingForeignKeysInfo.FirstOrDefault();
                        if (targetReferencingFKInfo is not null &&
                            objectTypes.TryGetValue(targetEntityName, out ObjectTypeDefinitionNode? targetObjectTypeDefinitionNode))
                        {
                            Dictionary<string, FieldDefinitionNode> targetFieldDefinitions = targetObjectTypeDefinitionNode.Fields.ToDictionary(field => field.Name.Value, field => field);
                            // When target entity is the referencing entity, referencing field directive is to be added to relationship fields
                            // in the target entity.
                            AddReferencingFieldDirectiveToReferencingFields(targetFieldDefinitions, targetReferencingFKInfo.ReferencingColumns, sqlMetadataProvider, targetEntityName);

                            // Update the target object definition with the new set of fields having referencing field directive.
                            objectTypes[targetEntityName] = targetObjectTypeDefinitionNode.WithFields(new List<FieldDefinitionNode>(targetFieldDefinitions.Values));
                        }
                    }
                }

                // Update the source object definition with the new set of fields having referencing field directive.
                objectTypes[sourceEntityName] = sourceObjectTypeDefinitionNode.WithFields(new List<FieldDefinitionNode>(sourceFieldDefinitions.Values));
            }
        }