@@ -18,6 +18,9 @@ public class ArrayPropertyValues : PropertyValues
1818 private readonly List < ArrayPropertyValues ? > ? [ ] _complexCollectionValues ;
1919 private readonly bool [ ] ? _nullComplexPropertyFlags ;
2020
21+ private static readonly bool UseOldBehavior37516 =
22+ AppContext . TryGetSwitch ( "Microsoft.EntityFrameworkCore.Issue37516" , out var enabled ) && enabled ;
23+
2124 /// <summary>
2225 /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
2326 /// the same compatibility standards as public APIs. It may be changed or removed without notice in
@@ -50,7 +53,7 @@ public override object ToObject()
5053 if ( _nullComplexPropertyFlags [ i ] )
5154 {
5255 var complexProperty = NullableComplexProperties [ i ] ;
53- structuralObject = ( ( IRuntimeComplexProperty ) complexProperty ) . GetSetter ( ) . SetClrValue ( structuralObject , null ) ;
56+ structuralObject = SetNestedComplexPropertyValue ( structuralObject , complexProperty , null ) ;
5457 }
5558 }
5659 }
@@ -68,7 +71,7 @@ public override object ToObject()
6871 ! complexProperty . IsShadowProperty ( ) ,
6972 $ "Shadow complex property { complexProperty . Name } is not supported. Issue #31243") ;
7073 var list = ( IList ) ( ( IRuntimeComplexProperty ) complexProperty ) . GetIndexedCollectionAccessor ( ) . Create ( propertyValuesList . Count ) ;
71- structuralObject = ( ( IRuntimeComplexProperty ) complexProperty ) . GetSetter ( ) . SetClrValue ( structuralObject , list ) ;
74+ structuralObject = SetNestedComplexPropertyValue ( structuralObject , complexProperty , list ) ;
7275
7376 foreach ( var propertyValues in propertyValuesList )
7477 {
@@ -79,6 +82,33 @@ public override object ToObject()
7982 return structuralObject ;
8083 }
8184
85+ private object SetNestedComplexPropertyValue ( object structuralObject , IComplexProperty complexProperty , object ? value )
86+ {
87+ return UseOldBehavior37516
88+ ? ( ( IRuntimeComplexProperty ) complexProperty ) . GetSetter ( ) . SetClrValue ( structuralObject , value )
89+ : SetValueRecursively ( structuralObject , complexProperty . GetChainToComplexProperty ( fromEntity : false ) , 0 , value ) ;
90+
91+ static object SetValueRecursively ( object instance , IReadOnlyList < IComplexProperty > chain , int index , object ? value )
92+ {
93+ var currentProperty = ( IRuntimeComplexProperty ) chain [ index ] ;
94+ if ( index == chain . Count - 1 )
95+ {
96+ return currentProperty . GetSetter ( ) . SetClrValue ( instance , value ) ;
97+ }
98+
99+ var child = currentProperty . GetGetter ( ) . GetClrValue ( instance ) ;
100+ if ( child == null )
101+ {
102+ return instance ;
103+ }
104+
105+ var updated = SetValueRecursively ( child , chain , index + 1 , value ) ;
106+ // Need to update the child value as well because it could be a value type
107+ // TODO: Improve this, see #36041
108+ return currentProperty . GetSetter ( ) . SetClrValue ( instance , updated ) ;
109+ }
110+ }
111+
82112 /// <summary>
83113 /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
84114 /// the same compatibility standards as public APIs. It may be changed or removed without notice in
@@ -495,20 +525,44 @@ ArrayPropertyValues CreateComplexPropertyValues(object complexObject, InternalCo
495525 for ( var i = 0 ; i < properties . Count ; i ++ )
496526 {
497527 var property = properties [ i ] ;
498- var getter = property . GetGetter ( ) ;
499- values [ i ] = getter . GetClrValue ( complexObject ) ;
528+ var targetObject = NavigateToDeclaringType ( complexObject , property . DeclaringType , complexType ) ;
529+ values [ i ] = targetObject == null ? null : property . GetGetter ( ) . GetClrValue ( targetObject ) ;
500530 }
501531
502532 var complexPropertyValues = new ArrayPropertyValues ( entry , values , null ) ;
503533
504534 foreach ( var nestedComplexProperty in complexPropertyValues . ComplexCollectionProperties )
505535 {
506- var nestedCollection = ( IList ? ) nestedComplexProperty . GetGetter ( ) . GetClrValue ( complexObject ) ;
507- var propertyValuesList = GetComplexCollectionPropertyValues ( nestedComplexProperty , nestedCollection ) ;
508- complexPropertyValues . SetComplexCollectionValue ( nestedComplexProperty , propertyValuesList ) ;
536+ var targetObject = NavigateToDeclaringType ( complexObject , nestedComplexProperty . DeclaringType , complexType ) ;
537+ var nestedCollection = targetObject == null ? null : ( IList ? ) nestedComplexProperty . GetGetter ( ) . GetClrValue ( targetObject ) ;
538+ var nestedPropertyValuesList = GetComplexCollectionPropertyValues ( nestedComplexProperty , nestedCollection ) ;
539+ complexPropertyValues . SetComplexCollectionValue ( nestedComplexProperty , nestedPropertyValuesList ) ;
509540 }
510541
511542 return complexPropertyValues ;
512543 }
544+
545+ static object ? NavigateToDeclaringType ( object root , ITypeBase declaringType , IRuntimeTypeBase rootType )
546+ {
547+ if ( declaringType == rootType
548+ || UseOldBehavior37516 )
549+ {
550+ return root ;
551+ }
552+
553+ if ( declaringType is not IComplexType ct )
554+ {
555+ return root ;
556+ }
557+
558+ var chain = ct . ComplexProperty . GetChainToComplexProperty ( fromEntity : false ) ;
559+ object ? target = root ;
560+ for ( var i = 0 ; i < chain . Count && target != null ; i ++ )
561+ {
562+ target = chain [ i ] . GetGetter ( ) . GetClrValue ( target ) ;
563+ }
564+
565+ return target ;
566+ }
513567 }
514568}
0 commit comments