diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/EdmModelExtensions.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/EdmModelExtensions.cs index 9eb3378b..e758e759 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/EdmModelExtensions.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/EdmModelExtensions.cs @@ -152,6 +152,7 @@ public static IEnumerable FindAllBaseTypes(this IEdmComplexType /// Type of the base type. /// Type of the sub type. /// true, if the is assignable to . Otherwise returns false. + [Obsolete] public static bool IsAssignableFrom(this IEdmEntityType baseType, IEdmEntityType subtype) { Utils.CheckArgumentNull(baseType, nameof(baseType)); diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs index b1cb8742..77324149 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs @@ -324,11 +324,30 @@ private void RetrieveMediaEntityStreamPaths(IEdmEntityType entityType, ODataPath /// The count restrictions. /// The current OData path. /// The settings for the current conversion. - private void RetrieveNavigationPropertyPaths(IEdmNavigationProperty navigationProperty, CountRestrictionsType count, ODataPath currentPath, OpenApiConvertSettings convertSettings) + /// A stack that holds the visited navigation properties in the . + private void RetrieveNavigationPropertyPaths( + IEdmNavigationProperty navigationProperty, + CountRestrictionsType count, + ODataPath currentPath, + OpenApiConvertSettings convertSettings, + Stack visitedNavigationProperties = null) { Debug.Assert(navigationProperty != null); Debug.Assert(currentPath != null); + if (visitedNavigationProperties == null) + { + visitedNavigationProperties = new (); + } + + var navPropFullyQualifiedName = $"{navigationProperty.DeclaringType.FullTypeName()}/{navigationProperty.Name}"; + + // Check whether the navigation property has already been navigated in the path + if (visitedNavigationProperties.Contains(navPropFullyQualifiedName)) + { + return; + } + // Check whether the navigation property should be part of the path NavigationRestrictionsType navigation = _model.GetRecord(navigationProperty, CapabilitiesConstants.NavigationRestrictions); if (navigation != null && !navigation.IsNavigable) @@ -336,12 +355,13 @@ private void RetrieveNavigationPropertyPaths(IEdmNavigationProperty navigationPr return; } - // test the expandable for the navigation property. - bool shouldExpand = ShouldExpandNavigationProperty(navigationProperty, currentPath); + // Whether to expand the navigation property + bool shouldExpand = navigationProperty.ContainsTarget; // append a navigation property. currentPath.Push(new ODataNavigationPropertySegment(navigationProperty)); AppendPath(currentPath.Clone()); + visitedNavigationProperties.Push(navPropFullyQualifiedName); // Check whether a collection-valued navigation property should be indexed by key value(s). NavigationPropertyRestriction restriction = navigation?.RestrictedProperties?.FirstOrDefault(); @@ -412,7 +432,7 @@ private void RetrieveNavigationPropertyPaths(IEdmNavigationProperty navigationPr { if (CanFilter(subNavProperty)) { - RetrieveNavigationPropertyPaths(subNavProperty, count, currentPath, convertSettings); + RetrieveNavigationPropertyPaths(subNavProperty, count, currentPath, convertSettings, visitedNavigationProperties); } } } @@ -421,35 +441,11 @@ private void RetrieveNavigationPropertyPaths(IEdmNavigationProperty navigationPr if (targetsMany) { currentPath.Pop(); - } + } } currentPath.Pop(); - } - - private bool ShouldExpandNavigationProperty(IEdmNavigationProperty navigationProperty, ODataPath currentPath) - { - Debug.Assert(navigationProperty != null); - Debug.Assert(currentPath != null); - - // not expand for the non-containment. - if (!navigationProperty.ContainsTarget) - { - return false; - } - - // check the type is visited before, if visited, not expand it. - IEdmEntityType navEntityType = navigationProperty.ToEntityType(); - foreach (ODataSegment segment in currentPath) - { - if (segment.EntityType != null && - navEntityType.IsAssignableFrom(segment.EntityType)) - { - return false; - } - } - - return true; - } + visitedNavigationProperties.Pop(); + } /// /// Create $ref paths. diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Edm/ODataPathProviderTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Edm/ODataPathProviderTests.cs index 2d5b997b..aae0001c 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Edm/ODataPathProviderTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Edm/ODataPathProviderTests.cs @@ -48,7 +48,7 @@ public void GetPathsForGraphBetaModelReturnsAllPaths() // Assert Assert.NotNull(paths); - Assert.Equal(28227, paths.Count()); + Assert.Equal(26436, paths.Count()); } [Fact] @@ -67,7 +67,7 @@ public void GetPathsForGraphBetaModelWithDerivedTypesConstraintReturnsAllPaths() // Assert Assert.NotNull(paths); - Assert.Equal(28193, paths.Count()); + Assert.Equal(26394, paths.Count()); } [Fact] diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Graph.Beta.OData.xml b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Graph.Beta.OData.xml index 23d80eb6..e8b90f17 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Graph.Beta.OData.xml +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Graph.Beta.OData.xml @@ -7495,11 +7495,6 @@ microsoft.graph.orgContact - - - - - @@ -7804,7 +7799,7 @@ - + @@ -8125,11 +8120,11 @@ - + - + @@ -13883,7 +13878,7 @@ - + @@ -13913,9 +13908,9 @@ - + - + @@ -15729,7 +15724,7 @@ - + @@ -15743,14 +15738,14 @@ - + - + @@ -25187,8 +25182,8 @@ - - + + @@ -25197,7 +25192,7 @@ - + @@ -25221,7 +25216,7 @@ - + @@ -25516,7 +25511,7 @@ - + @@ -25533,7 +25528,7 @@ - + @@ -25549,7 +25544,7 @@ - + @@ -25558,8 +25553,8 @@ - - + + @@ -25571,7 +25566,7 @@ - + @@ -71201,7 +71196,7 @@ - +