@@ -204,53 +204,59 @@ private object SetHasOneRelationship(object entity,
204204 if ( relationships . TryGetValue ( relationshipName , out RelationshipData relationshipData ) == false )
205205 return entity ;
206206
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-
213207 var rio = ( ResourceIdentifierObject ) relationshipData . ExposedData ;
214208
215209 var foreignKey = attr . IdentifiablePropertyName ;
216210 var foreignKeyProperty = entityProperties . FirstOrDefault ( p => p . Name == foreignKey ) ;
217-
218211 if ( foreignKeyProperty == null && rio == null )
219212 return entity ;
220213
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 ) ;
228216
229- var newValue = rio ? . Id ?? null ;
230- var convertedValue = TypeHelper . ConvertType ( newValue , foreignKeyProperty . PropertyType ) ;
217+ return entity ;
218+ }
231219
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)
233227
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.") ;
235232
233+ var convertedValue = TypeHelper . ConvertType ( foreignKeyPropertyValue , foreignKeyProperty . PropertyType ) ;
234+ foreignKeyProperty . SetValue ( entity , convertedValue ) ;
235+ _jsonApiContext . RelationshipsToUpdate [ hasOneAttr ] = convertedValue ;
236+ }
237+ }
236238
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 )
240248 {
241249 // we have now set the FK property on the resource, now we need to check to see if the
242250 // 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 ) ;
244252 if ( includedRelationshipObject != null )
245- relationshipAttr . SetValue ( entity , includedRelationshipObject ) ;
253+ hasOneAttr . SetValue ( entity , includedRelationshipObject ) ;
246254
247255 // we need to store the fact that this relationship was included in the payload
248256 // for EF, the repository will use these pointers to make ensure we don't try to
249257 // 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 ) ;
251259 }
252-
253- return entity ;
254260 }
255261
256262 private object SetHasManyRelationship ( object entity ,
0 commit comments