Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 32 additions & 10 deletions src/Core/Configurations/RuntimeConfigValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -323,10 +323,22 @@ public void ValidateRelationshipConfigCorrectness(RuntimeConfig runtimeConfig)
if (entity.Source.Type is not EntitySourceType.Table && entity.Relationships is not null
&& entity.Relationships.Count > 0)
{
HandleOrRecordException(new DataApiBuilderException(
message: $"Cannot define relationship for entity: {entityName}",
statusCode: HttpStatusCode.ServiceUnavailable,
subStatusCode: DataApiBuilderException.SubStatusCodes.ConfigValidationError));
// Views are allowed to have relationships only for MSSQL and DWSQL databases.
// Stored procedures cannot have relationships.
string databaseNameForEntity = runtimeConfig.GetDataSourceNameFromEntityName(entityName);
DatabaseType dbType = runtimeConfig.GetDataSourceFromDataSourceName(databaseNameForEntity).DatabaseType;

bool isViewWithRelationshipAllowed = entity.Source.Type is EntitySourceType.View
&& (dbType is DatabaseType.MSSQL or DatabaseType.DWSQL);

if (!isViewWithRelationshipAllowed)
{
HandleOrRecordException(new DataApiBuilderException(
message: $"Cannot define relationship for entity: {entityName}. " +
$"Relationships are only supported for tables, or for views when using MSSQL or DWSQL databases.",
statusCode: HttpStatusCode.ServiceUnavailable,
subStatusCode: DataApiBuilderException.SubStatusCodes.ConfigValidationError));
}
}

string databaseName = runtimeConfig.GetDataSourceNameFromEntityName(entityName);
Expand Down Expand Up @@ -1067,10 +1079,20 @@ public void ValidateRelationships(RuntimeConfig runtimeConfig, IMetadataProvider
continue;
}

DatabaseTable sourceDatabaseObject = (DatabaseTable)sourceObject;
DatabaseTable targetDatabaseObject = (DatabaseTable)targetObject;
// Source and target objects can be tables or views (for MSSQL/DWSQL)
DatabaseObject sourceDatabaseObject = sourceObject;
DatabaseObject targetDatabaseObject = targetObject;

// For RelationShipPair comparisons, we convert to DatabaseTable since the comparison
// only uses schema and name (not the actual type)
DatabaseTable sourceDatabaseTable = sourceDatabaseObject as DatabaseTable
?? new DatabaseTable(sourceDatabaseObject.SchemaName, sourceDatabaseObject.Name);
DatabaseTable targetDatabaseTable = targetDatabaseObject as DatabaseTable
?? new DatabaseTable(targetDatabaseObject.SchemaName, targetDatabaseObject.Name);

if (relationship.LinkingObject is not null)
{
// Linking object must remain a table
(string linkingTableSchema, string linkingTableName) = sqlMetadataProvider.ParseSchemaAndDbTableName(relationship.LinkingObject)!;
DatabaseTable linkingDatabaseObject = new(linkingTableSchema, linkingTableName);

Expand Down Expand Up @@ -1103,8 +1125,8 @@ public void ValidateRelationships(RuntimeConfig runtimeConfig, IMetadataProvider
string sourceDBOName = sqlMetadataProvider.EntityToDatabaseObject[entityName].FullName;
string targetDBOName = sqlMetadataProvider.EntityToDatabaseObject[relationship.TargetEntity].FullName;
string cardinality = relationship.Cardinality.ToString().ToLower();
RelationShipPair linkedSourceRelationshipPair = new(linkingDatabaseObject, sourceDatabaseObject);
RelationShipPair linkedTargetRelationshipPair = new(linkingDatabaseObject, targetDatabaseObject);
RelationShipPair linkedSourceRelationshipPair = new(linkingDatabaseObject, sourceDatabaseTable);
RelationShipPair linkedTargetRelationshipPair = new(linkingDatabaseObject, targetDatabaseTable);
ForeignKeyDefinition? fKDef;
string referencedSourceColumns = relationship.SourceFields is not null ? string.Join(",", relationship.SourceFields) :
sqlMetadataProvider.PairToFkDefinition!.TryGetValue(linkedSourceRelationshipPair, out fKDef) ?
Expand Down Expand Up @@ -1150,8 +1172,8 @@ public void ValidateRelationships(RuntimeConfig runtimeConfig, IMetadataProvider

if (relationship.LinkingObject is null && !_runtimeConfigProvider.IsLateConfigured)
{
RelationShipPair sourceTargetRelationshipPair = new(sourceDatabaseObject, targetDatabaseObject);
RelationShipPair targetSourceRelationshipPair = new(targetDatabaseObject, sourceDatabaseObject);
RelationShipPair sourceTargetRelationshipPair = new(sourceDatabaseTable, targetDatabaseTable);
RelationShipPair targetSourceRelationshipPair = new(targetDatabaseTable, sourceDatabaseTable);
string sourceDBOName = sqlMetadataProvider.EntityToDatabaseObject[entityName].FullName;
string targetDBOName = sqlMetadataProvider.EntityToDatabaseObject[relationship.TargetEntity].FullName;
string cardinality = relationship.Cardinality.ToString().ToLower();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -498,8 +498,8 @@ public IQueryBuilder GetQueryBuilder()
}

public bool VerifyForeignKeyExistsInDB(
DatabaseTable databaseTableA,
DatabaseTable databaseTableB)
DatabaseObject databaseObjectA,
DatabaseObject databaseObjectB)
{
throw new NotImplementedException();
}
Expand Down
4 changes: 2 additions & 2 deletions src/Core/Services/MetadataProviders/ISqlMetadataProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ public interface ISqlMetadataProvider
string GetSchemaName(string entityName);

bool VerifyForeignKeyExistsInDB(
DatabaseTable databaseObjectA,
DatabaseTable databaseObjectB);
DatabaseObject databaseObjectA,
DatabaseObject databaseObjectB);

/// <summary>
/// Obtains the underlying source object's name (SQL table or Cosmos container).
Expand Down
Loading