Skip to content

Commit

Permalink
Fixes #2737: Support getting navigation source for complex types (#2744)
Browse files Browse the repository at this point in the history
Merging, as no substantive changes were made since Sam's approval.
  • Loading branch information
mikepizzo authored Feb 4, 2023
1 parent d8c66b6 commit 3bbc7d9
Show file tree
Hide file tree
Showing 3 changed files with 326 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ internal static ODataDeserializerContext GenerateNestedReadContext(ODataNestedRe
segmentType = readContext.Model.FindType(propertyTypeName);
}

// could it be a problem later that the navigationSource is null?
DynamicPathSegment pathSegment = new DynamicPathSegment(
nestedResourceInfo.Name,
segmentType,
Expand All @@ -79,12 +78,12 @@ internal static ODataDeserializerContext GenerateNestedReadContext(ODataNestedRe
{
if (edmProperty.PropertyKind == EdmPropertyKind.Navigation)
{
Contract.Assert(readContext.Path.NavigationSource != null, "Navigation property segment with null navigationSource");
IEdmNavigationProperty navigationProperty = edmProperty as IEdmNavigationProperty;
IEdmNavigationSource parentNavigationSource = readContext.Path.NavigationSource;
IEdmNavigationSource navigationSource = parentNavigationSource.FindNavigationTarget(navigationProperty);
IEdmPathExpression bindingPath = GetBindingPath(readContext.Path, navigationProperty);
IEdmNavigationSource navigationSource = parentNavigationSource?.FindNavigationTarget(navigationProperty, bindingPath);

if (navigationProperty.ContainsTarget)
if (navigationProperty.ContainsTarget || navigationSource == null || navigationSource is IEdmUnknownEntitySet)
{
path = AppendToPath(path, new NavigationPropertySegment(navigationProperty, navigationSource), navigationProperty.DeclaringType, parentNavigationSource);
}
Expand All @@ -110,6 +109,44 @@ internal static ODataDeserializerContext GenerateNestedReadContext(ODataNestedRe
return BuildNestedContextFromCurrentContext(readContext, path);
}

// Determines the binding path for an OData Path to a given navigationProperty
private static IEdmPathExpression GetBindingPath(Routing.ODataPath path, IEdmNavigationProperty navigationProperty)
{
Contract.Assert(navigationProperty != null, "Called GetBindingPath with a null navigation property");
if (path == null)
{
return null;
}

// Binding Path is made up of complex types, containment navigation properties, and type segments
List<string> segments = new List<string>();
foreach (ODataPathSegment segment in path.Segments)
{
if (segment is NavigationPropertySegment navSegment)
{
segments.Add(navSegment.NavigationProperty.Name);
}
else if (segment is PropertySegment propertySegment)
{
segments.Add(propertySegment.Property.Name);
}
else if (segment is TypeSegment typeSegment)
{
segments.Add(typeSegment.Identifier);
}
}

if(navigationProperty.DeclaringType != path.EdmType as IEdmStructuredType)
{
// Add a type cast segment
segments.Add(navigationProperty.DeclaringType.FullTypeName());
}

segments.Add(navigationProperty.Name);

return new EdmPathExpression(String.Join("/", segments));
}

/// <summary>
/// It builds a nested deserializer context from the current deserializer context
/// </summary>
Expand Down Expand Up @@ -154,11 +191,13 @@ internal static Routing.ODataPath AppendToPath(Routing.ODataPath path, ODataPath
}

List<ODataPathSegment> segments = new List<ODataPathSegment>(path.Segments);
IEdmType pathType = path.EdmType;

// Append type cast segment if required
if (declaringType != null && path.EdmType != declaringType)
if (declaringType != null && pathType != null && pathType != declaringType
&& declaringType.IsOrInheritsFrom(pathType.AsElementType()))
{
segments.Add(new TypeSegment(declaringType, navigationSource));
segments.Add(new TypeSegment(declaringType, pathType, navigationSource));
}

segments.Add(segment);
Expand Down
Loading

0 comments on commit 3bbc7d9

Please sign in to comment.