Skip to content

Saving an Entity with an IPoint with Ordinates.XYZ in SpatiaLite throws an exception #14257

@cmiles

Description

@cmiles

Using EFCore/NTS/SpatiaLite creating a table from an entity containing an IPoint property built with .ForSqliteHasDimension(Ordinates.XYZ) works as expected but trying to save an entity to the table fails with '[point] violates Geometry constraint [geom-type or SRID not allowed]'. This failure occurs with both
Microsoft.EntityFrameworkCore.Sqlite.NetTopologySuite 2.2 or 3.0.0-preview.18572.1 .

Exception message:
Error Saving New Xyz Point Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while updating the entries. See the inner exception for details. ---> Microsoft.Data.Sqlite.SqliteException: SQLite Error 19: 'Xyzs.XyzPoint violates Geometry constraint [geom-type or SRID not allowed]'.

Stack trace:
   at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)
   at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior behavior)
   at Microsoft.Data.Sqlite.SqliteCommand.ExecuteDbDataReader(CommandBehavior behavior)
   at System.Data.Common.DbCommand.ExecuteReader()
   at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.Execute(IRelationalConnection connection, DbCommandMethod executeMethod, IReadOnlyDictionary`2 parameterValues)
   at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.ExecuteReader(IRelationalConnection connection, IReadOnlyDictionary`2 parameterValues)
   at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.Execute(IRelationalConnection connection)
   --- End of inner exception stack trace ---
   at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.Execute(IRelationalConnection connection)
   at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.Execute(DbContext _, ValueTuple`2 parameters)
   at Microsoft.EntityFrameworkCore.Storage.Internal.NoopExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
   at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.Execute(IEnumerable`1 commandBatches, IRelationalConnection connection)
   at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChanges(IReadOnlyList`1 entries)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(IReadOnlyList`1 entriesToSave)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(Boolean acceptAllChangesOnSuccess)
   at Microsoft.EntityFrameworkCore.DbContext.SaveChanges(Boolean acceptAllChangesOnSuccess)
   at ConsoleTest.Program.Main(String[] args) in C:\Code\SpatialiteXyzPointTestEfCore\ConsoleTest\Program.cs:line 95

Steps to reproduce

Create a new netcoreapp3.0 console project, add Microsoft.EntityFrameworkCore.Sqlite, Microsoft.EntityFrameworkCore.Sqlite.NetTopologySuite (either 2.2 or 3 preview) and mod_spatialite.

Create an entity with an IPoint property with .ForSqliteHasSrid(4326) and .ForSqliteHasDimension(Ordinates.XYZ).

Create the db, set the IPoint property and save - an error is thrown.

'Show Spatial Metadata' in the spatialite_gui on the generated column reports:
f_geometry_column xyzpoint
geometry_type 1001
coord_dimension 3
srid 4326

There are quite a few details here that I don't have much experience with but to try to eliminate general database/code errors and srid as issues the code sample also builds an XY point - which saves without error. I did wonder about the geometry_type of 1001 vs 1 for an xypoint is expected by EF...

The zipped solution and project included uses the code below to show the issue.

SpatialiteXyzPointTestEfCore.zip

using System;
using GeoAPI.Geometries;
using Microsoft.EntityFrameworkCore;
using NetTopologySuite;
using NetTopologySuite.Geometries;

namespace ConsoleTest
{
    public class SpatialTestContext : DbContext
    {
        public DbSet<Xy> Xys { get; set; }
        public DbSet<Xyz> Xyzs { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.EnableSensitiveDataLogging();
            optionsBuilder.UseSqlite("Filename=./Xyz.sqlite", x => x.UseNetTopologySuite());
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Xy>().Property(c => c.XyPoint)
                .ForSqliteHasSrid(4326);
            modelBuilder.Entity<Xy>().Property(c => c.XyPoint)
                .ForSqliteHasDimension(Ordinates.XY);

            modelBuilder.Entity<Xyz>().Property(c => c.XyzPoint)
                .ForSqliteHasSrid(4326);
            modelBuilder.Entity<Xyz>().Property(c => c.XyzPoint)
                .ForSqliteHasDimension(Ordinates.XYZ);
        }
    }

    public class Xy
    {
        public int Id { get; set; }
        public string Note { get; set; }
        public IPoint XyPoint { get; set; }
    }

    public class Xyz
    {
        public int Id { get; set; }
        public string Note { get; set; }
        public IPoint XyzPoint { get; set; }
    }

    internal class Program
    {
        private static void Main(string[] args)
        {
            using (var context = new SpatialTestContext())
            {
                context.Database.EnsureDeleted();
                context.Database.EnsureCreated();

                Console.WriteLine($"Create New Xy Point");

                var geometryFactory = NtsGeometryServices.Instance.CreateGeometryFactory(srid: 4326);
                var xyLocation = geometryFactory.CreatePoint(new Coordinate(-122.121512, 47.6739882));

                var newXyPoint = new Xy
                {
                    Note = $"{DateTime.Now} New Xy Point",
                    XyPoint = xyLocation
                };

                context.Xys.Add(newXyPoint);

                try
                {
                    Console.WriteLine($"Saving New Xy Point");
                    context.SaveChanges(true);
                }
                catch (Exception e)
                {
                    Console.WriteLine($"Error Saving New Xy Point {e}");
                }

                Console.WriteLine($"Create New Xyz Point");

                var xyzPoint = geometryFactory.CreatePoint(new Coordinate(-122.121512, 47.6739882, 1000));

                var newXyzPoint = new Xyz
                {
                    Note = $"{DateTime.Now} New Xyz Point",
                    XyzPoint = xyzPoint
                };

                context.Xyzs.Add(newXyzPoint);

                try
                {
                    Console.WriteLine($"Saving New Xyz Point");
                    context.SaveChanges(true);
                }
                catch (Exception e)
                {
                    Console.WriteLine($"Error Saving New Xyz Point {e}");
                }
            }
        }
    }
}

Further technical details

EF Core version: netcoreapp3.0
Database Provider: Microsoft.EntityFrameworkCore.Sqlite.NetTopologySuite
Operating system: Win10 1809
IDE: VS 2019 Version 16.0.0 Preview 1.1

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions