diff --git a/Directory.Packages.props b/Directory.Packages.props
index 1a5f1f0dce..dc3a3b92a6 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -2,7 +2,7 @@
7.0.0-preview.7.22359.1
7.0.0-preview.6.22354.1
- 7.0.0-preview.5
+ 7.0.0-preview.6-ci.20220710T074055
diff --git a/src/EFCore.PG.NTS/Query/ExpressionTranslators/Internal/NpgsqlNetTopologySuiteAggregateMethodCallTranslatorPlugin.cs b/src/EFCore.PG.NTS/Query/ExpressionTranslators/Internal/NpgsqlNetTopologySuiteAggregateMethodCallTranslatorPlugin.cs
index a55ead2974..91ee33ebc2 100644
--- a/src/EFCore.PG.NTS/Query/ExpressionTranslators/Internal/NpgsqlNetTopologySuiteAggregateMethodCallTranslatorPlugin.cs
+++ b/src/EFCore.PG.NTS/Query/ExpressionTranslators/Internal/NpgsqlNetTopologySuiteAggregateMethodCallTranslatorPlugin.cs
@@ -36,6 +36,9 @@ private static readonly MethodInfo ConvexHullMethod
private static readonly MethodInfo UnionMethod
= typeof(UnaryUnionOp).GetRuntimeMethod(nameof(UnaryUnionOp.Union), new[] { typeof(IEnumerable) })!;
+ private static readonly MethodInfo EnvelopeCombineMethod
+ = typeof(EnvelopeCombiner).GetRuntimeMethod(nameof(EnvelopeCombiner.CombineAsGeometry), new[] { typeof(IEnumerable) })!;
+
private readonly NpgsqlSqlExpressionFactory _sqlExpressionFactory;
private readonly IRelationalTypeMappingSource _typeMappingSource;
@@ -51,44 +54,65 @@ public NpgsqlNetTopologySuiteAggregateMethodTranslator(
MethodInfo method, EnumerableExpression source, IReadOnlyList arguments,
IDiagnosticsLogger logger)
{
- if (source.Selector is not SqlExpression sqlExpression
- || (method != GeometryCombineMethod && method != UnionMethod && method != ConvexHullMethod))
+ if (source.Selector is not SqlExpression sqlExpression)
{
return null;
}
- var resultTypeMapping = _typeMappingSource.FindMapping(typeof(Geometry), sqlExpression.TypeMapping?.StoreType ?? "geometry");
-
- if (method == GeometryCombineMethod || method == UnionMethod)
+ if (method == ConvexHullMethod)
{
- return _sqlExpressionFactory.AggregateFunction(
- method == GeometryCombineMethod ? "ST_Collect" : "ST_Union",
- new[] { sqlExpression },
- source,
+ // PostGIS has no built-in aggregate convex hull, but we can simply apply ST_Collect beforehand as recommended in the docs
+ // https://postgis.net/docs/ST_ConvexHull.html
+ return _sqlExpressionFactory.Function(
+ "ST_ConvexHull",
+ new[]
+ {
+ _sqlExpressionFactory.AggregateFunction(
+ "ST_Collect",
+ new[] { sqlExpression },
+ source,
+ nullable: true,
+ argumentsPropagateNullability: new[] { false },
+ typeof(Geometry),
+ GetMapping())
+ },
nullable: true,
- argumentsPropagateNullability: new[] { false },
+ argumentsPropagateNullability: new[] { true },
typeof(Geometry),
- resultTypeMapping);
+ GetMapping());
}
- // PostGIS has no built-in aggregate convex hull, but we can simply apply ST_Collect beforehand as recommended in the docs
- // https://postgis.net/docs/ST_ConvexHull.html
- return _sqlExpressionFactory.Function(
- "ST_ConvexHull",
- new[]
- {
+ if (method == EnvelopeCombineMethod)
+ {
+ // ST_Extent returns a PostGIS box2d, which isn't a geometry and has no binary output function.
+ // Convert it to a geometry first.
+ return _sqlExpressionFactory.Convert(
_sqlExpressionFactory.AggregateFunction(
- "ST_Collect",
+ "ST_Extent",
new[] { sqlExpression },
source,
nullable: true,
argumentsPropagateNullability: new[] { false },
typeof(Geometry),
- resultTypeMapping)
- },
- nullable: true,
- argumentsPropagateNullability: new[] { true },
- typeof(Geometry),
- resultTypeMapping);
+ GetMapping()),
+ typeof(Geometry), GetMapping());
+ }
+
+ if (method == UnionMethod || method == GeometryCombineMethod)
+ {
+ return _sqlExpressionFactory.AggregateFunction(
+ method == UnionMethod ? "ST_Union" : "ST_Collect",
+ new[] { sqlExpression },
+ source,
+ nullable: true,
+ argumentsPropagateNullability: new[] { false },
+ typeof(Geometry),
+ GetMapping());
+ }
+
+ return null;
+
+ RelationalTypeMapping? GetMapping()
+ => _typeMappingSource.FindMapping(typeof(Geometry), sqlExpression.TypeMapping?.StoreType ?? "geometry");
}
}
diff --git a/src/EFCore.PG/Storage/Internal/NpgsqlRelationalConnection.cs b/src/EFCore.PG/Storage/Internal/NpgsqlRelationalConnection.cs
index 767c55e3f2..a452d9055b 100644
--- a/src/EFCore.PG/Storage/Internal/NpgsqlRelationalConnection.cs
+++ b/src/EFCore.PG/Storage/Internal/NpgsqlRelationalConnection.cs
@@ -47,7 +47,9 @@ protected override DbConnection CreateDbConnection()
if (ProvidePasswordCallback is not null)
{
+#pragma warning disable 618 // ProvidePasswordCallback is obsolete
conn.ProvidePasswordCallback = ProvidePasswordCallback;
+#pragma warning restore 618
}
return conn;
diff --git a/test/EFCore.PG.FunctionalTests/Query/SpatialQueryNpgsqlGeometryTest.cs b/test/EFCore.PG.FunctionalTests/Query/SpatialQueryNpgsqlGeometryTest.cs
index 240f970da2..3d7875a504 100644
--- a/test/EFCore.PG.FunctionalTests/Query/SpatialQueryNpgsqlGeometryTest.cs
+++ b/test/EFCore.PG.FunctionalTests/Query/SpatialQueryNpgsqlGeometryTest.cs
@@ -91,6 +91,17 @@ public override async Task Combine_aggregate(bool async)
GROUP BY p.""Group""");
}
+ public override async Task EnvelopeCombine_aggregate(bool async)
+ {
+ await base.EnvelopeCombine_aggregate(async);
+
+ AssertSql(
+ @"SELECT p.""Group"" AS ""Id"", ST_Extent(p.""Point"")::geometry AS ""Combined""
+FROM ""PointEntity"" AS p
+WHERE (p.""Point"" IS NOT NULL)
+GROUP BY p.""Group""");
+ }
+
public override async Task Contains(bool async)
{
await base.Contains(async);