@@ -206,30 +206,50 @@ protected override ShapedQueryExpression TransformJsonQueryToTable(JsonQueryExpr
206206 var columnInfos = new List < PgTableValuedFunctionExpression . ColumnInfo > ( ) ;
207207
208208 // We're only interested in properties which actually exist in the JSON, filter out uninteresting shadow keys
209- foreach ( var property in GetAllPropertiesInHierarchy ( jsonQueryExpression . EntityType ) )
209+ foreach ( var property in jsonQueryExpression . StructuralType . GetPropertiesInHierarchy ( ) )
210210 {
211211 if ( property . GetJsonPropertyName ( ) is string jsonPropertyName )
212212 {
213213 columnInfos . Add (
214214 new PgTableValuedFunctionExpression . ColumnInfo
215215 {
216- Name = jsonPropertyName , TypeMapping = property . GetRelationalTypeMapping ( )
216+ Name = jsonPropertyName ,
217+ TypeMapping = property . GetRelationalTypeMapping ( )
217218 } ) ;
218219 }
219220 }
220221
221- // Navigations represent nested JSON owned entities, which we also add to the AS clause, but with the JSON type.
222- foreach ( var navigation in GetAllNavigationsInHierarchy ( jsonQueryExpression . EntityType )
223- . Where (
224- n => n . ForeignKey . IsOwnership
225- && n . TargetEntityType . IsMappedToJson ( )
226- && n . ForeignKey . PrincipalToDependent == n ) )
222+ switch ( jsonQueryExpression . StructuralType )
227223 {
228- var jsonNavigationName = navigation . TargetEntityType . GetJsonPropertyName ( ) ;
229- Check . DebugAssert ( jsonNavigationName is not null , $ "No JSON property name for navigation { navigation . Name } ") ;
224+ case IEntityType entityType :
225+ foreach ( var navigation in entityType . GetNavigationsInHierarchy ( )
226+ . Where ( n => n . ForeignKey . IsOwnership
227+ && n . TargetEntityType . IsMappedToJson ( )
228+ && n . ForeignKey . PrincipalToDependent == n ) )
229+ {
230+ var jsonNavigationName = navigation . TargetEntityType . GetJsonPropertyName ( ) ;
231+ Check . DebugAssert ( jsonNavigationName is not null , $ "No JSON property name for navigation { navigation . Name } ") ;
232+
233+ columnInfos . Add (
234+ new PgTableValuedFunctionExpression . ColumnInfo { Name = jsonNavigationName , TypeMapping = jsonTypeMapping } ) ;
235+ }
236+
237+ break ;
238+
239+ case IComplexType complexType :
240+ foreach ( var complexProperty in complexType . GetComplexProperties ( ) )
241+ {
242+ var jsonPropertyName = complexProperty . ComplexType . GetJsonPropertyName ( ) ;
243+ Check . DebugAssert ( jsonPropertyName is not null , $ "No JSON property name for complex property { complexProperty . Name } ") ;
244+
245+ columnInfos . Add (
246+ new PgTableValuedFunctionExpression . ColumnInfo { Name = jsonPropertyName , TypeMapping = jsonTypeMapping } ) ;
247+ }
230248
231- columnInfos . Add (
232- new PgTableValuedFunctionExpression . ColumnInfo { Name = jsonNavigationName , TypeMapping = jsonTypeMapping } ) ;
249+ break ;
250+
251+ default :
252+ throw new UnreachableException ( ) ;
233253 }
234254
235255 // json_to_recordset requires the nested JSON document - it does not accept a path within a containing JSON document (like SQL
@@ -254,21 +274,12 @@ protected override ShapedQueryExpression TransformJsonQueryToTable(JsonQueryExpr
254274 return new ShapedQueryExpression (
255275 selectExpression ,
256276 new RelationalStructuralTypeShaperExpression (
257- jsonQueryExpression . EntityType ,
277+ jsonQueryExpression . StructuralType ,
258278 new ProjectionBindingExpression (
259279 selectExpression ,
260280 new ProjectionMember ( ) ,
261281 typeof ( ValueBuffer ) ) ,
262282 false ) ) ;
263-
264- // TODO: Move these to IEntityType?
265- static IEnumerable < IProperty > GetAllPropertiesInHierarchy ( IEntityType entityType )
266- => entityType . GetAllBaseTypes ( ) . Concat ( entityType . GetDerivedTypesInclusive ( ) )
267- . SelectMany ( t => t . GetDeclaredProperties ( ) ) ;
268-
269- static IEnumerable < INavigation > GetAllNavigationsInHierarchy ( IEntityType entityType )
270- => entityType . GetAllBaseTypes ( ) . Concat ( entityType . GetDerivedTypesInclusive ( ) )
271- . SelectMany ( t => t . GetDeclaredNavigations ( ) ) ;
272283 }
273284
274285 /// <summary>
@@ -1096,46 +1107,18 @@ protected override bool IsValidSelectExpressionForExecuteUpdate(
10961107 /// any release. You should only use it directly in your code with extreme caution and knowing that
10971108 /// doing so can result in application failures when updating to a new Entity Framework Core release.
10981109 /// </summary>
1099- protected override bool IsValidSelectExpressionForExecuteDelete (
1100- SelectExpression selectExpression ,
1101- StructuralTypeShaperExpression shaper ,
1102- [ NotNullWhen ( true ) ] out TableExpression ? tableExpression )
1103- {
1104- // The default relational behavior is to allow only single-table expressions, and the only permitted feature is a predicate.
1105- // Here we extend this to also inner joins to tables, which we generate via the KingbaseES-specific USING construct.
1106- if ( selectExpression is
1107- {
1108- Orderings : [ ] ,
1109- Offset : null ,
1110- Limit : null ,
1111- GroupBy : [ ] ,
1112- Having : null
1113- } )
1114- {
1115- TableExpressionBase ? table = null ;
1116- if ( selectExpression . Tables . Count == 1 )
1117- {
1118- table = selectExpression . Tables [ 0 ] ;
1119- }
1120- else if ( selectExpression . Tables . All ( t => t is TableExpression or InnerJoinExpression ) )
1121- {
1122- var projectionBindingExpression = ( ProjectionBindingExpression ) shaper . ValueBufferExpression ;
1123- var entityProjectionExpression =
1124- ( StructuralTypeProjectionExpression ) selectExpression . GetProjection ( projectionBindingExpression ) ;
1125- var column = entityProjectionExpression . BindProperty ( shaper . StructuralType . GetProperties ( ) . First ( ) ) ;
1126- table = selectExpression . Tables . Select ( t => t . UnwrapJoin ( ) ) . Single ( t => t . Alias == column . TableAlias ) ;
1127- }
1128-
1129- if ( table is TableExpression te )
1130- {
1131- tableExpression = te ;
1132- return true ;
1133- }
1134- }
1135-
1136- tableExpression = null ;
1137- return false ;
1138- }
1110+ protected override bool IsValidSelectExpressionForExecuteDelete ( SelectExpression selectExpression )
1111+ // The default relational behavior is to allow only single-table expressions, and the only permitted feature is a predicate.
1112+ // Here we extend this to also inner joins to tables, which we generate via the PostgreSQL-specific USING construct.
1113+ => selectExpression is
1114+ {
1115+ Orderings : [ ] ,
1116+ Offset : null ,
1117+ Limit : null ,
1118+ GroupBy : [ ] ,
1119+ Having : null
1120+ }
1121+ && selectExpression . Tables [ 0 ] is TableExpression && selectExpression . Tables . Skip ( 1 ) . All ( t => t is InnerJoinExpression ) ;
11391122
11401123 // KingbaseES unnest is guaranteed to return output rows in the same order as its input array,
11411124 // https://www.KingbaseES.org/docs/current/functions-array.html.
0 commit comments