@@ -93,38 +93,40 @@ internal static bool NavigationRestrictionsAllowsNavigability(
93
93
/// Generates the operation id from a navigation property path.
94
94
/// </summary>
95
95
/// <param name="path">The target <see cref="ODataPath"/>.</param>
96
+ /// <param name="context">The OData context.</param>
96
97
/// <param name="prefix">Optional: Identifier indicating whether it is a collection-valued non-indexed or single-valued navigation property.</param>
97
98
/// <returns>The operation id generated from the given navigation property path.</returns>
98
- internal static string GenerateNavigationPropertyPathOperationId ( ODataPath path , string prefix = null )
99
+ internal static string GenerateNavigationPropertyPathOperationId ( ODataPath path , ODataContext context , string prefix = null )
99
100
{
100
- IList < string > items = RetrieveNavigationPropertyPathsOperationIdSegments ( path ) ;
101
+ IList < string > items = RetrieveNavigationPropertyPathsOperationIdSegments ( path , context ) ;
101
102
102
103
if ( ! items . Any ( ) )
103
104
return null ;
104
105
105
- int lastItemIndex = items . Count - 1 ;
106
+ int lastItemIndex = items [ ^ 1 ] . StartsWith ( '-' ) ? items . Count - 2 : items . Count - 1 ;
106
107
107
108
if ( ! string . IsNullOrEmpty ( prefix ) )
108
109
{
109
- items [ lastItemIndex ] = prefix + Utils . UpperFirstChar ( items . Last ( ) ) ;
110
+ items [ lastItemIndex ] = prefix + Utils . UpperFirstChar ( items [ lastItemIndex ] ) ;
110
111
}
111
112
else
112
113
{
113
- items [ lastItemIndex ] = Utils . UpperFirstChar ( items . Last ( ) ) ;
114
+ items [ lastItemIndex ] = Utils . UpperFirstChar ( items [ lastItemIndex ] ) ;
114
115
}
115
116
116
- return string . Join ( "." , items ) ;
117
+ return GenerateNavigationPropertyPathOperationId ( items ) ;
117
118
}
118
119
119
120
/// <summary>
120
121
/// Generates the operation id from a complex property path.
121
122
/// </summary>
122
123
/// <param name="path">The target <see cref="ODataPath"/>.</param>
124
+ /// <param name="context">The OData context.</param>
123
125
/// <param name="prefix">Optional: Identifier indicating whether it is a collection-valued or single-valued complex property.</param>
124
126
/// <returns>The operation id generated from the given complex property path.</returns>
125
- internal static string GenerateComplexPropertyPathOperationId ( ODataPath path , string prefix = null )
127
+ internal static string GenerateComplexPropertyPathOperationId ( ODataPath path , ODataContext context , string prefix = null )
126
128
{
127
- IList < string > items = RetrieveNavigationPropertyPathsOperationIdSegments ( path ) ;
129
+ IList < string > items = RetrieveNavigationPropertyPathsOperationIdSegments ( path , context ) ;
128
130
129
131
if ( ! items . Any ( ) )
130
132
return null ;
@@ -141,15 +143,29 @@ internal static string GenerateComplexPropertyPathOperationId(ODataPath path, st
141
143
items . Add ( Utils . UpperFirstChar ( lastSegment ? . Identifier ) ) ;
142
144
}
143
145
144
- return string . Join ( "." , items ) ;
146
+ return GenerateNavigationPropertyPathOperationId ( items ) ;
147
+ }
148
+
149
+ /// <summary>
150
+ /// Generates a navigation property operation id from a list of string values.
151
+ /// </summary>
152
+ /// <param name="items">The list of string values.</param>
153
+ /// <returns>The generated navigation property operation id.</returns>
154
+ private static string GenerateNavigationPropertyPathOperationId ( IList < string > items )
155
+ {
156
+ if ( ! items . Any ( ) )
157
+ return null ;
158
+
159
+ return string . Join ( "." , items ) . Replace ( ".-" , "-" , StringComparison . OrdinalIgnoreCase ) ; // Format any hashed value appropriately (this will be the last value)
145
160
}
146
161
147
162
/// <summary>
148
163
/// Retrieves the segments of an operation id generated from a navigation property path.
149
164
/// </summary>
150
165
/// <param name="path">The target <see cref="ODataPath"/>.</param>
166
+ /// <param name="context">The OData context.</param>
151
167
/// <returns>The segments of an operation id generated from the given navigation property path.</returns>
152
- internal static IList < string > RetrieveNavigationPropertyPathsOperationIdSegments ( ODataPath path )
168
+ internal static IList < string > RetrieveNavigationPropertyPathsOperationIdSegments ( ODataPath path , ODataContext context )
153
169
{
154
170
Utils . CheckArgumentNull ( path , nameof ( path ) ) ;
155
171
@@ -173,6 +189,8 @@ s is ODataOperationSegment ||
173
189
Utils . CheckArgumentNull ( segments , nameof ( segments ) ) ;
174
190
175
191
string previousTypeCastSegmentId = null ;
192
+ string pathHash = string . Empty ;
193
+
176
194
foreach ( var segment in segments )
177
195
{
178
196
if ( segment is ODataNavigationPropertySegment navPropSegment )
@@ -192,6 +210,14 @@ s is ODataOperationSegment ||
192
210
else if ( segment is ODataOperationSegment operationSegment )
193
211
{
194
212
// Navigation property generated via composable function
213
+ if ( operationSegment . Operation is IEdmFunction function && context . Model . IsOperationOverload ( function ) )
214
+ {
215
+ // Hash the segment to avoid duplicate operationIds
216
+ pathHash = string . IsNullOrEmpty ( pathHash )
217
+ ? operationSegment . GetPathHash ( context . Settings )
218
+ : ( pathHash + operationSegment . GetPathHash ( context . Settings ) ) . GetHashSHA256 ( ) [ ..4 ] ;
219
+ }
220
+
195
221
items . Add ( operationSegment . Identifier ) ;
196
222
}
197
223
else if ( segment is ODataKeySegment keySegment && keySegment . IsAlternateKey )
@@ -208,6 +234,11 @@ s is ODataOperationSegment ||
208
234
}
209
235
}
210
236
237
+ if ( ! string . IsNullOrEmpty ( pathHash ) )
238
+ {
239
+ items . Add ( "-" + pathHash ) ;
240
+ }
241
+
211
242
return items ;
212
243
}
213
244
@@ -320,9 +351,10 @@ internal static string GenerateComplexPropertyPathTagName(ODataPath path, ODataC
320
351
/// Generates the operation id prefix from an OData type cast path.
321
352
/// </summary>
322
353
/// <param name="path">The target <see cref="ODataPath"/>.</param>
354
+ /// <param name="context">The OData context.</param>
323
355
/// <param name="includeListOrGetPrefix">Optional: Whether to include the List or Get prefix to the generated operation id.</param>
324
356
/// <returns>The operation id prefix generated from the OData type cast path.</returns>
325
- internal static string GenerateODataTypeCastPathOperationIdPrefix ( ODataPath path , bool includeListOrGetPrefix = true )
357
+ internal static string GenerateODataTypeCastPathOperationIdPrefix ( ODataPath path , ODataContext context , bool includeListOrGetPrefix = true )
326
358
{
327
359
// Get the segment before the last OData type cast segment
328
360
ODataTypeCastSegment typeCastSegment = path . Segments . OfType < ODataTypeCastSegment > ( ) ? . Last ( ) ;
@@ -352,7 +384,7 @@ internal static string GenerateODataTypeCastPathOperationIdPrefix(ODataPath path
352
384
if ( secondLastSegment is ODataComplexPropertySegment complexSegment )
353
385
{
354
386
string listOrGet = includeListOrGetPrefix ? ( complexSegment . Property . Type . IsCollection ( ) ? "List" : "Get" ) : null ;
355
- operationId = GenerateComplexPropertyPathOperationId ( path , listOrGet ) ;
387
+ operationId = GenerateComplexPropertyPathOperationId ( path , context , listOrGet ) ;
356
388
}
357
389
else if ( secondLastSegment is ODataNavigationPropertySegment navPropSegment )
358
390
{
@@ -362,13 +394,13 @@ internal static string GenerateODataTypeCastPathOperationIdPrefix(ODataPath path
362
394
prefix = navPropSegment ? . NavigationProperty . TargetMultiplicity ( ) == EdmMultiplicity . Many ? "List" : "Get" ;
363
395
}
364
396
365
- operationId = GenerateNavigationPropertyPathOperationId ( path , prefix ) ;
397
+ operationId = GenerateNavigationPropertyPathOperationId ( path , context , prefix ) ;
366
398
}
367
399
else if ( secondLastSegment is ODataKeySegment keySegment )
368
400
{
369
401
if ( isIndexedCollValuedNavProp )
370
402
{
371
- operationId = GenerateNavigationPropertyPathOperationId ( path , "Get" ) ;
403
+ operationId = GenerateNavigationPropertyPathOperationId ( path , context , "Get" ) ;
372
404
}
373
405
else
374
406
{
0 commit comments