Skip to content

Commit 3bbc7d9

Browse files
authored
Fixes #2737: Support getting navigation source for complex types (#2744)
Merging, as no substantive changes were made since Sam's approval.
1 parent d8c66b6 commit 3bbc7d9

3 files changed

Lines changed: 326 additions & 25 deletions

File tree

src/Microsoft.AspNet.OData.Shared/Formatter/Deserialization/ODataResourceDeserializerHelpers.cs

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@ internal static ODataDeserializerContext GenerateNestedReadContext(ODataNestedRe
6666
segmentType = readContext.Model.FindType(propertyTypeName);
6767
}
6868

69-
// could it be a problem later that the navigationSource is null?
7069
DynamicPathSegment pathSegment = new DynamicPathSegment(
7170
nestedResourceInfo.Name,
7271
segmentType,
@@ -79,12 +78,12 @@ internal static ODataDeserializerContext GenerateNestedReadContext(ODataNestedRe
7978
{
8079
if (edmProperty.PropertyKind == EdmPropertyKind.Navigation)
8180
{
82-
Contract.Assert(readContext.Path.NavigationSource != null, "Navigation property segment with null navigationSource");
8381
IEdmNavigationProperty navigationProperty = edmProperty as IEdmNavigationProperty;
8482
IEdmNavigationSource parentNavigationSource = readContext.Path.NavigationSource;
85-
IEdmNavigationSource navigationSource = parentNavigationSource.FindNavigationTarget(navigationProperty);
83+
IEdmPathExpression bindingPath = GetBindingPath(readContext.Path, navigationProperty);
84+
IEdmNavigationSource navigationSource = parentNavigationSource?.FindNavigationTarget(navigationProperty, bindingPath);
8685

87-
if (navigationProperty.ContainsTarget)
86+
if (navigationProperty.ContainsTarget || navigationSource == null || navigationSource is IEdmUnknownEntitySet)
8887
{
8988
path = AppendToPath(path, new NavigationPropertySegment(navigationProperty, navigationSource), navigationProperty.DeclaringType, parentNavigationSource);
9089
}
@@ -110,6 +109,44 @@ internal static ODataDeserializerContext GenerateNestedReadContext(ODataNestedRe
110109
return BuildNestedContextFromCurrentContext(readContext, path);
111110
}
112111

112+
// Determines the binding path for an OData Path to a given navigationProperty
113+
private static IEdmPathExpression GetBindingPath(Routing.ODataPath path, IEdmNavigationProperty navigationProperty)
114+
{
115+
Contract.Assert(navigationProperty != null, "Called GetBindingPath with a null navigation property");
116+
if (path == null)
117+
{
118+
return null;
119+
}
120+
121+
// Binding Path is made up of complex types, containment navigation properties, and type segments
122+
List<string> segments = new List<string>();
123+
foreach (ODataPathSegment segment in path.Segments)
124+
{
125+
if (segment is NavigationPropertySegment navSegment)
126+
{
127+
segments.Add(navSegment.NavigationProperty.Name);
128+
}
129+
else if (segment is PropertySegment propertySegment)
130+
{
131+
segments.Add(propertySegment.Property.Name);
132+
}
133+
else if (segment is TypeSegment typeSegment)
134+
{
135+
segments.Add(typeSegment.Identifier);
136+
}
137+
}
138+
139+
if(navigationProperty.DeclaringType != path.EdmType as IEdmStructuredType)
140+
{
141+
// Add a type cast segment
142+
segments.Add(navigationProperty.DeclaringType.FullTypeName());
143+
}
144+
145+
segments.Add(navigationProperty.Name);
146+
147+
return new EdmPathExpression(String.Join("/", segments));
148+
}
149+
113150
/// <summary>
114151
/// It builds a nested deserializer context from the current deserializer context
115152
/// </summary>
@@ -154,11 +191,13 @@ internal static Routing.ODataPath AppendToPath(Routing.ODataPath path, ODataPath
154191
}
155192

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

158196
// Append type cast segment if required
159-
if (declaringType != null && path.EdmType != declaringType)
197+
if (declaringType != null && pathType != null && pathType != declaringType
198+
&& declaringType.IsOrInheritsFrom(pathType.AsElementType()))
160199
{
161-
segments.Add(new TypeSegment(declaringType, navigationSource));
200+
segments.Add(new TypeSegment(declaringType, pathType, navigationSource));
162201
}
163202

164203
segments.Add(segment);

0 commit comments

Comments
 (0)