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));
}
}