@@ -204,53 +204,59 @@ private object SetHasOneRelationship(object entity,
204
204
if ( relationships . TryGetValue ( relationshipName , out RelationshipData relationshipData ) == false )
205
205
return entity ;
206
206
207
- var relationshipAttr = _jsonApiContext . RequestEntity . Relationships
208
- . SingleOrDefault ( r => r . PublicRelationshipName == relationshipName ) ;
209
-
210
- if ( relationshipAttr == null )
211
- throw new JsonApiException ( 400 , $ "{ _jsonApiContext . RequestEntity . EntityName } does not contain a relationship '{ relationshipName } '") ;
212
-
213
207
var rio = ( ResourceIdentifierObject ) relationshipData . ExposedData ;
214
208
215
209
var foreignKey = attr . IdentifiablePropertyName ;
216
210
var foreignKeyProperty = entityProperties . FirstOrDefault ( p => p . Name == foreignKey ) ;
217
-
218
211
if ( foreignKeyProperty == null && rio == null )
219
212
return entity ;
220
213
221
- if ( foreignKeyProperty == null && rio != null )
222
- throw new JsonApiException ( 400 , $ "{ contextEntity . EntityType . Name } does not contain a foreign key property '{ foreignKey } ' for has one relationship '{ attr . InternalRelationshipName } '") ;
223
-
224
- // e.g. PATCH /articles
225
- // {... { "relationships":{ "Owner": { "data": null } } } }
226
- if ( rio == null && Nullable . GetUnderlyingType ( foreignKeyProperty . PropertyType ) == null )
227
- throw new JsonApiException ( 400 , $ "Cannot set required relationship identifier '{ attr . IdentifiablePropertyName } ' to null because it is a non-nullable type.") ;
214
+ SetHasOneForeignKeyValue ( entity , attr , foreignKeyProperty , rio ) ;
215
+ SetHasOneNavigationPropertyValue ( entity , attr , rio , included ) ;
228
216
229
- var newValue = rio ? . Id ?? null ;
230
- var convertedValue = TypeHelper . ConvertType ( newValue , foreignKeyProperty . PropertyType ) ;
217
+ return entity ;
218
+ }
231
219
232
- _jsonApiContext . RelationshipsToUpdate [ relationshipAttr ] = convertedValue ;
220
+ private void SetHasOneForeignKeyValue ( object entity , HasOneAttribute hasOneAttr , PropertyInfo foreignKeyProperty , ResourceIdentifierObject rio )
221
+ {
222
+ var foreignKeyPropertyValue = rio ? . Id ?? null ;
223
+ if ( foreignKeyProperty != null )
224
+ {
225
+ // in the case of the HasOne independent side of the relationship, we should still create the shell entity on the other side
226
+ // we should not actually require the resource to have a foreign key (be the dependent side of the relationship)
233
227
234
- foreignKeyProperty . SetValue ( entity , convertedValue ) ;
228
+ // e.g. PATCH /articles
229
+ // {... { "relationships":{ "Owner": { "data": null } } } }
230
+ if ( rio == null && Nullable . GetUnderlyingType ( foreignKeyProperty . PropertyType ) == null )
231
+ throw new JsonApiException ( 400 , $ "Cannot set required relationship identifier '{ hasOneAttr . IdentifiablePropertyName } ' to null because it is a non-nullable type.") ;
235
232
233
+ var convertedValue = TypeHelper . ConvertType ( foreignKeyPropertyValue , foreignKeyProperty . PropertyType ) ;
234
+ foreignKeyProperty . SetValue ( entity , convertedValue ) ;
235
+ _jsonApiContext . RelationshipsToUpdate [ hasOneAttr ] = convertedValue ;
236
+ }
237
+ }
236
238
237
- if ( rio != null
238
- // if the resource identifier is null, there should be no reason to instantiate an instance
239
- && rio . Id != null )
239
+ /// <summary>
240
+ /// Sets the value of the navigation property for the related resource.
241
+ /// If the resource has been included, all attributes will be set.
242
+ /// If the resource has not been included, only the id will be set.
243
+ /// </summary>
244
+ private void SetHasOneNavigationPropertyValue ( object entity , HasOneAttribute hasOneAttr , ResourceIdentifierObject rio , List < DocumentData > included )
245
+ {
246
+ // if the resource identifier is null, there should be no reason to instantiate an instance
247
+ if ( rio != null && rio . Id != null )
240
248
{
241
249
// we have now set the FK property on the resource, now we need to check to see if the
242
250
// related entity was included in the payload and update its attributes
243
- var includedRelationshipObject = GetIncludedRelationship ( rio , included , relationshipAttr ) ;
251
+ var includedRelationshipObject = GetIncludedRelationship ( rio , included , hasOneAttr ) ;
244
252
if ( includedRelationshipObject != null )
245
- relationshipAttr . SetValue ( entity , includedRelationshipObject ) ;
253
+ hasOneAttr . SetValue ( entity , includedRelationshipObject ) ;
246
254
247
255
// we need to store the fact that this relationship was included in the payload
248
256
// for EF, the repository will use these pointers to make ensure we don't try to
249
257
// create resources if they already exist, we just need to create the relationship
250
- _jsonApiContext . HasOneRelationshipPointers . Add ( attr , includedRelationshipObject ) ;
258
+ _jsonApiContext . HasOneRelationshipPointers . Add ( hasOneAttr , includedRelationshipObject ) ;
251
259
}
252
-
253
- return entity ;
254
260
}
255
261
256
262
private object SetHasManyRelationship ( object entity ,
0 commit comments