NTS translations that use the wrong PostGIS function or drop an argument: `EqualsExact`, `Buffer(d, EndCapStyle)`, `Length`, `NumPoints`, `Combine`, `EnvelopeCombiner`
Los mantenedores suelen responder en 1 día
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Aptitud para principiantes
- 70/100
Línea de trabajo
Start by reading the three translator plugins referenced: NpgsqlNetTopologySuiteMethodCallTranslatorPlugin.cs, NpgsqlNetTopologySuiteMemberTranslatorPlugin.cs, and NpgsqlNetTopologySuiteAggregateMethodCallTranslatorPlugin.cs at the cited lines. Adjust the SQL generation for EqualsExact, Buffer, Length, NumPoints, GeometryCombiner.Combine, and EnvelopeCombiner.CombineAsGeometry to match NTS semantics. Done when the LINQ-to-PostGIS translations produce results identical to the .NET outputs shown.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
| Environment | |
|---|---|
| PostgreSQL | 18.6 with PostGIS 3.6.4 and GEOS 3.14.1 (postgis/postgis:18-3.6), session TimeZone Etc/UTC |
| .NET 10 | runtime 10.0.11, Npgsql.EntityFrameworkCore.PostgreSQL.NetTopologySuite 10.0.3, EF Core 10.0.4 |
| .NET 11 | runtime 11.0.0-rc.2, Npgsql.EntityFrameworkCore.PostgreSQL.NetTopologySuite 11.0.0-rc.2, EF Core 11.0.0-rc.2 |
| Also | Npgsql 10.0.3 on both lines, NetTopologySuite 2.6.0, Npgsql.NetTopologySuite 10.0.3, macOS arm64 |
Both lines print the same output. main at 150011d has the same code.
| LINQ | Row | .NET | PostgreSQL | SQL |
|---|---|---|---|---|
r.Point.EqualsExact(near, 0.5) |
POINT (1 2), near = POINT (1.1 2) |
match | no match | ST_OrderingEquals(r."Point", @near) |
r.Line.Buffer(1, EndCapStyle.Flat).Area |
LINESTRING (0 0, 10 0) |
20.00 | 22.83 | ST_Area(ST_Buffer(r."Line", 1.0, 2)) |
r.Polygon.Length |
a 4×4 square | 16 | 0 | ST_Length(r."Polygon") |
r.Polygon.NumPoints |
same | 5 | NULL | ST_NumPoints(r."Polygon") |
GeometryCombiner.Combine(g.Select(r => r.Multi)) |
two MultiPoints | MultiPoint |
GeometryCollection of 2 |
ST_Collect(r0."Multi") |
EnvelopeCombiner.CombineAsGeometry(...) .SRID |
SRID 4326 input | 4326 | −1 | ST_Extent(r0."Polygon")::geometry |
Repro
using System.Globalization;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using NetTopologySuite.Geometries;
using NetTopologySuite.Geometries.Utilities;
using NetTopologySuite.Operation.Buffer;
CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
var f = new GeometryFactory(new PrecisionModel(), 4326);
await using var context = new TestContext();
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();
context.Rows.AddRange(
new Row
{
Point = f.CreatePoint(new Coordinate(1, 2)),
Line = f.CreateLineString([new(0, 0), new(10, 0)]),
Polygon = f.CreatePolygon([new(0, 0), new(4, 0), new(4, 4), new(0, 4), new(0, 0)]),
Multi = f.CreateMultiPointFromCoords([new(0, 0), new(1, 1)]),
},
new Row
{
Point = f.CreatePoint(new Coordinate(5, 5)),
Line = f.CreateLineString([new(0, 0), new(0, 10)]),
Polygon = f.CreatePolygon([new(0, 0), new(1, 0), new(1, 1), new(0, 1), new(0, 0)]),
Multi = f.CreateMultiPointFromCoords([new(2, 2), new(3, 3)]),
});
await context.SaveChangesAsync();
var rows = await context.Rows.AsNoTracking().OrderBy(r => r.Id).ToListAsync();
var row = rows[0];
var near = f.CreatePoint(new Coordinate(1.1, 2));
// 1. The tolerance is dropped: ST_OrderingEquals(a, b)
Console.WriteLine($"Point.EqualsExact(near, 0.5): .NET {rows.Count(r => r.Point.EqualsExact(near, 0.5))}, database {await context.Rows.CountAsync(r => r.Point.EqualsExact(near, 0.5))}");
// 2. The cap style is passed as ST_Buffer's integer quad_segs argument
Console.WriteLine($"Line.Buffer(1, EndCapStyle.Flat).Area: .NET {row.Line.Buffer(1, EndCapStyle.Flat).Area:F2}, database {await context.Rows.OrderBy(r => r.Id).Select(r => r.Line.Buffer(1, EndCapStyle.Flat).Area).FirstAsync():F2}");
// 3. ST_Length is 0 for polygons; NTS and SQL Server return the perimeter
Console.WriteLine($"Polygon.Length: .NET {row.Polygon.Length}, database {await context.Rows.OrderBy(r => r.Id).Select(r => r.Polygon.Length).FirstAsync()}");
// 4. ST_NumPoints is NULL for anything but a LineString; ST_NPoints counts every geometry
Console.WriteLine($"Polygon.NumPoints: .NET {row.Polygon.NumPoints}, database {(await context.Rows.OrderBy(r => r.Id).Select(r => (int?)r.Polygon.NumPoints).FirstAsync())?.ToString() ?? "NULL"}");
// 5. ST_Collect nests collections; GeometryCombiner flattens them
var combined = await context.Rows.GroupBy(r => 1).Select(g => GeometryCombiner.Combine(g.Select(r => (Geometry)r.Multi))).SingleAsync();
Console.WriteLine($"GeometryCombiner.Combine(MultiPoints): .NET {GeometryCombiner.Combine(rows.Select(r => (Geometry)r.Multi)).GeometryType}, database {combined.GeometryType} of {combined.NumGeometries}");
// 6. ST_Extent returns a box2d, which has no SRID
var envelope = await context.Rows.GroupBy(r => 1).Select(g => EnvelopeCombiner.CombineAsGeometry(g.Select(r => (Geometry)r.Polygon))).SingleAsync();
Console.WriteLine($"EnvelopeCombiner.CombineAsGeometry(...).SRID: .NET {EnvelopeCombiner.CombineAsGeometry(rows.Select(r => (Geometry)r.Polygon)).SRID}, database {envelope.SRID}");
public class TestContext : DbContext
{
public DbSet<Row> Rows => Set<Row>();
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseNpgsql(Environment.GetEnvironmentVariable("Test__Npgsql__DefaultConnection"), o => o.UseNetTopologySuite())
.LogTo(Console.WriteLine, LogLevel.Information)
.EnableSensitiveDataLogging();
protected override void OnModelCreating(ModelBuilder modelBuilder)
=> modelBuilder.HasPostgresExtension("postgis");
}
public class Row
{
public int Id { get; set; }
public Point Point { get; set; }
public LineString Line { get; set; }
public Polygon Polygon { get; set; }
public MultiPoint Multi { get; set; }
}
Output, the same on both lines:
Point.EqualsExact(near, 0.5): .NET 1, database 0
Line.Buffer(1, EndCapStyle.Flat).Area: .NET 20.00, database 22.83
Polygon.Length: .NET 16, database 0
Polygon.NumPoints: .NET 5, database NULL
GeometryCombiner.Combine(MultiPoints): .NET MultiPoint, database GeometryCollection of 2
EnvelopeCombiner.CombineAsGeometry(...).SRID: .NET 4326, database -1
EqualsExact(g, tolerance): both overloads map toST_OrderingEquals(instance, arguments[0])(NpgsqlNetTopologySuiteMethodCallTranslatorPlugin.cs#L214-L215), and the tolerance is dropped.ST_OrderingEqualshas no tolerance, so the overload probably shouldn't be translated.Buffer(distance, EndCapStyle): all arguments are passed through (NpgsqlNetTopologySuiteMethodCallTranslatorPlugin.cs#L196-L197). The enum becomes an integer, which resolves toST_Buffer(geometry, float8, integer quad_segs). PostGIS takes the cap style as a parameter string ('endcap=flat').Lengthmaps toST_Lengthfor every geometry (NpgsqlNetTopologySuiteMemberTranslatorPlugin.cs#L158). PostGIS returns 0 for areal geometries;ST_Perimetergives what NTS returns.NumPointsmaps toST_NumPoints(NpgsqlNetTopologySuiteMemberTranslatorPlugin.cs#L161), which PostGIS 3 defines for LineStrings only.ST_NPointscounts the vertices of any geometry.GeometryCombiner.Combinemaps toST_Collect(NpgsqlNetTopologySuiteAggregateMethodCallTranslatorPlugin.cs#L141-L148), which nests collection inputs; NTS flattens them into one collection.EnvelopeCombiner.CombineAsGeometrymaps toST_Extent(...)::geometry(NpgsqlNetTopologySuiteAggregateMethodCallTranslatorPlugin.cs#L122-L138). Abox2dcarries no SRID, so the result loses it.
- Lenguaje dominante
- C#
- Estrellas
- 1.8k
- Forks
- 268
- Merge medio
- 2 h 35 min
- PR fusionados (30 d)
- 136
Preparar el entorno
Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de npgsql/efcore.pg
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
Los mantenedores suelen responder en 1 día
-
NTS: the M ordinate is dropped from geometry SQL literals and from geometries stored in JSONPosiblemente ocupada @Ahmed7991 la tomó hace 5 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 85/100
npgsql/efcore.pg#4093 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
`TimeSpan`/`Duration` component members: negative values are floored, and intervals computed in SQL are read field by fieldPosiblemente ocupada @jeremy-morren la tomó hace 11 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 70/100
Los mantenedores suelen responder en 1 día
-
Numeric storage parameters are formatted with the current culture, so migrations emit 0,01 instead of 0.01Posiblemente ocupada @Sorbitol la tomó hace 12 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 30/100
Los mantenedores suelen responder en 1 día
-
`Contains` on a JSON primitive collection compares JSON text, so `DateTime` and `TimeOnly` items never matchPosiblemente ocupada @Mr444-dev la tomó hace 7 días. Abierto
Dificultad 4/5 3-5 días Aptitud para principiantes 45/100
npgsql/efcore.pg#4099 · 1 comentario ·
Los mantenedores suelen responder en 1 día
Todos los issues de npgsql/efcore.pg
Issues similares
-
Issue-Bug Needs-Triage
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
Los mantenedores suelen responder en 2 días
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 66/100
JiaFeiMiao-K-Cat/DiscImageStudio#281 ·
Los mantenedores suelen responder en 1 día
-
area/access-management Frontend onboarding candidate :handshake:
Dificultad 2/5 1-3 horas Aptitud para principiantes 65/100
Altinn/altinn-auth#4941 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
aws/aws-sdk-net#4586 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
Kryptos-FR/MarkView.Avalonia#269 · 1 reacción ·
Los mantenedores suelen responder en 1 día