@@ -47,8 +47,6 @@ public NpgsqlNetTopologySuiteMethodCallTranslatorPlugin(
4747/// </summary>
4848public class NpgsqlGeometryMethodTranslator : IMethodCallTranslator
4949{
50- private static readonly MethodInfo _collectionItem = typeof ( GeometryCollection ) . GetRuntimeProperty ( "Item" ) ! . GetMethod ! ;
51-
5250 private readonly NpgsqlSqlExpressionFactory _sqlExpressionFactory ;
5351 private readonly IRelationalTypeMappingSource _typeMappingSource ;
5452
@@ -77,11 +75,31 @@ public NpgsqlGeometryMethodTranslator(
7775 MethodInfo method ,
7876 IReadOnlyList < SqlExpression > arguments ,
7977 IDiagnosticsLogger < DbLoggerCategory . Query > logger )
80- => method . DeclaringType == typeof ( NpgsqlNetTopologySuiteDbFunctionsExtensions )
81- ? TranslateDbFunction ( method , arguments )
82- : instance is not null && typeof ( Geometry ) . IsAssignableFrom ( method . DeclaringType )
83- ? TranslateGeometryMethod ( instance , method , arguments )
84- : null ;
78+ => method . DeclaringType switch
79+ {
80+ var t when typeof ( Geometry ) . IsAssignableFrom ( t ) && instance is not null
81+ => TranslateGeometryMethod ( instance , method , arguments ) ,
82+
83+ var t when t == typeof ( NpgsqlNetTopologySuiteDbFunctionsExtensions )
84+ => TranslateDbFunction ( method , arguments ) ,
85+
86+ // This handles the collection indexer (geom_collection[x] -> ST_GeometryN(geom_collection, x + 1))
87+ // This is needed as a special case because EF transforms the indexer into a call to Enumerable.ElementAt
88+ var t when t == typeof ( Enumerable )
89+ && method . Name is nameof ( Enumerable . ElementAt )
90+ && method . ReturnType == typeof ( Geometry )
91+ && arguments is [ var collection , var index ]
92+ && _typeMappingSource . FindMapping ( typeof ( Geometry ) , collection . TypeMapping ! . StoreType ) is RelationalTypeMapping geometryTypeMapping
93+ => _sqlExpressionFactory . Function (
94+ "ST_GeometryN" ,
95+ [ collection , OneBased ( index ) ] ,
96+ nullable : true ,
97+ argumentsPropagateNullability : TrueArrays [ 2 ] ,
98+ method . ReturnType ,
99+ geometryTypeMapping ) ,
100+
101+ _ => null
102+ } ;
85103
86104 private SqlExpression ? TranslateDbFunction (
87105 MethodInfo method ,
@@ -143,17 +161,6 @@ public NpgsqlGeometryMethodTranslator(
143161
144162 arguments = typeMappedArguments ;
145163
146- if ( Equals ( method , _collectionItem ) )
147- {
148- return _sqlExpressionFactory . Function (
149- "ST_GeometryN" ,
150- [ instance , OneBased ( arguments [ 0 ] ) ] ,
151- nullable : true ,
152- argumentsPropagateNullability : TrueArrays [ 2 ] ,
153- method . ReturnType ,
154- _typeMappingSource . FindMapping ( typeof ( Geometry ) , instance . TypeMapping ! . StoreType ) ) ;
155- }
156-
157164 return method . Name switch
158165 {
159166 nameof ( Geometry . AsBinary )
@@ -226,16 +233,16 @@ SqlExpression Function(string name, SqlExpression[] arguments, Type returnType,
226233 nullable : true , argumentsPropagateNullability : TrueArrays [ arguments . Length ] ,
227234 returnType , typeMapping ) ;
228235
229- // NetTopologySuite uses 0-based indexing, but PostGIS uses 1-based
230- SqlExpression OneBased ( SqlExpression arg )
231- => arg is SqlConstantExpression constant
232- ? _sqlExpressionFactory . Constant ( ( int ) constant . Value ! + 1 , constant . TypeMapping )
233- : _sqlExpressionFactory . Add ( arg , _sqlExpressionFactory . Constant ( 1 ) ) ;
234-
235236 RelationalTypeMapping ResultGeometryMapping ( )
236237 {
237238 Debug . Assert ( typeof ( Geometry ) . IsAssignableFrom ( method . ReturnType ) ) ;
238239 return _typeMappingSource . FindMapping ( method . ReturnType , storeType ) ! ;
239240 }
240241 }
242+
243+ // NetTopologySuite uses 0-based indexing, but PostGIS uses 1-based
244+ private SqlExpression OneBased ( SqlExpression arg )
245+ => arg is SqlConstantExpression constant
246+ ? _sqlExpressionFactory . Constant ( ( int ) constant . Value ! + 1 , constant . TypeMapping )
247+ : _sqlExpressionFactory . Add ( arg , _sqlExpressionFactory . Constant ( 1 ) ) ;
241248}
0 commit comments