Entity Framework преобразовывает геометрию в географию - PullRequest
2 голосов
/ 13 июля 2020

Я пытаюсь вставить объект Geometry через класс Entity в свою базу данных, но всегда возвращается ошибка «география несовместима с геометрией». Сначала я получаю строку, передающую значения X и Y того, что будет геометрической координатой, и делаю необходимые преобразования для создания типа Point, который предлагает Geometry, мне не нужно делать никаких вычислений, поэтому тип Geometry является лучшим для меня пользуйся прямо сейчас. Я использую приведенную ниже функцию для преобразования:

public static Geometry ConvertToGeometry(string coordinatesAux)
{
    if(coordinatesAux == null)
        throw new NullReferenceException();

    NumberFormatInfo formatProvider = new NumberFormatInfo();
    formatProvider.NumberGroupSeparator = ".";
        
    var geometryFactory = NtsGeometryServices.Instance.CreateGeometryFactory(srid: 4326);
    var currentLocation = geometryFactory.CreatePoint(new Coordinate(
                                                           Convert.ToDouble(coordinatesAux.Substring(0, coordinatesAux.IndexOf(",")), formatProvider), 
                                                           Convert.ToDouble(coordinatesAux.Substring(coordinatesAux.IndexOf(",") + 1), formatProvider)));
        
    return currentLocation;                                                            
}

Я также внес необходимые изменения в Startup.cs для db, чтобы использовать NetTopologySuite, но когда я пытаюсь вставить значение через API, он возвращает ошибка описана изначально. Я не знаю, заключается ли проблема в том, как я преобразовал строку в геометрию, или это сама сущность, которая распознает поле как точку географии.

Значение, которое я пытаюсь передать, это -20.338113, -40.287893 и класс Entity, который я использую:

public class Address : EntityBase<int>
{
    public Address(string district, string street, int number, string complement, string zipCode, 
    string cityDescription, string stateDescription, Geometry coordinates, int countryId, byte stateId, int cityId)
    {
        District = district;
        Street = street;
        Number = number;
        Complement = complement;
        ZipCode = zipCode;
        CityDescription = cityDescription;
        StateDescription = stateDescription;
        Coordinates = coordinates;
        CountryId = countryId;
        StateId = stateId;
        CityId = cityId;
    }

    public string District { get; set; }
    public string Street { get; set; }
    public int Number { get; set; }
    public string Complement { get; set; }
    public string ZipCode { get; set; }
    public string CityDescription { get; set; }
    public string StateDescription { get; set; }
    public virtual Geometry Coordinates { get; set; }
    public int CountryId { get; set; }
    public byte StateId { get; set; }
    public int CityId { get; set; }
    public int? CustomerId { get; set; }
    public int? StoreId { get; set; }
    public int? ProfessionalId { get; set; }
}

Итак, снова спрашивая, что-то делает структура Entity или я сделал ошибку? Если потребуется больше частей кода, я отредактирую вопрос, чтобы добавить.

Редактировать 1

Адрес таблицы:

CREATE TABLE Address(
    Id INT PRIMARY KEY IDENTITY(1, 1),
    District VARCHAR(50) NOT NULL, -- Bairro
    Street VARCHAR(100) NOT NULL, -- Rua
    --Description VARCHAR(100) NOT NULL,
    Number INT,
    Complement VARCHAR(100),
    ZipCode VARCHAR(20) NOT NULL,
    CityDescription VARCHAR(100),
    StateDescription VARCHAR(100),
    Coordinates GEOMETRY,
    
    CountryId INT FOREIGN KEY REFERENCES Country(Id) NOT NULL,
    StateId TINYINT FOREIGN KEY REFERENCES State(Id),
    CityId INT FOREIGN KEY REFERENCES City(Id),
    CustomerId INT FOREIGN KEY REFERENCES Customer(Id),
    StoreId INT FOREIGN KEY REFERENCES Store(Id),
    ProfessionalId INT FOREIGN KEY REFERENCES Professional(Id),

    INDEX IndexAddressCountryId NONCLUSTERED (CountryId),
    INDEX IndexAddressStateId NONCLUSTERED (StateId),
    INDEX IndexAddressCityId NONCLUSTERED (CityId),
    INDEX IndexAddressCustomerId NONCLUSTERED (CustomerId),
    INDEX IndexAddressStoreId NONCLUSTERED (StoreId),
    INDEX IndexAddressProfessionalId NONCLUSTERED (ProfessionalId)
)

1 Ответ

1 голос
/ 13 июля 2020

Вот пример, который отлично работает, отображая либо geometry, либо geography. Вам придется по-другому увидеть, что вы делаете. (И, кстати, вы, вероятно, захотите geography, поскольку geometry в SQL Server представляет собой плоское евклидово пространство и не даст вам точных вычислений расстояния или прямых линий для координат по широте и долготе).

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Common;
using System.Linq;
using System.Security.Cryptography;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using NetTopologySuite.Geometries;


namespace EfCore3Test
{

    public class Address : EntityBase<int>
    {
        public Address() { }
        public Address(string district, string street, int number, string complement, string zipCode,
        string cityDescription, string stateDescription, Geometry coordinates, int countryId, byte stateId, int cityId)
        {
            District = district;
            Street = street;
            Number = number;
            Complement = complement;
            ZipCode = zipCode;
            CityDescription = cityDescription;
            StateDescription = stateDescription;
            Coordinates = coordinates;
            CountryId = countryId;
            StateId = stateId;
            CityId = cityId;
        }

        public string District { get; set; }
        public string Street { get; set; }
        public int Number { get; set; }
        public string Complement { get; set; }
        public string ZipCode { get; set; }
        public string CityDescription { get; set; }
        public string StateDescription { get; set; }

        //[Column(TypeName ="geometry")]
        public virtual Geometry Coordinates { get; set; }
        public int CountryId { get; set; }
        public byte StateId { get; set; }
        public int CityId { get; set; }
        public int? CustomerId { get; set; }
        public int? StoreId { get; set; }
        public int? ProfessionalId { get; set; }
    }

    public class EntityBase<T>
    {
        public T Id { get; set; }
    }

    public class Db : DbContext
    {
           
        public Db(): base()
        {

        }

        private static readonly ILoggerFactory loggerFactory = LoggerFactory.Create(builder =>
        {
            builder.AddFilter((category, level) =>
               category == DbLoggerCategory.Database.Command.Name
               && level == LogLevel.Information).AddConsole();
        });
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            var constr = "Server = localhost; database = efcore3test; integrated security = true";
            optionsBuilder.UseLoggerFactory(loggerFactory)
                          .UseSqlServer(constr, o => o.UseRelationalNulls().UseNetTopologySuite());


            base.OnConfiguring(optionsBuilder);
        }

        public DbSet<Address> Addresses { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
        }

    }




    class Program
    {


    static void Main(string[] args)
        {
 

            using (var db = new Db())
            {

                db.Database.EnsureDeleted();
                db.Database.EnsureCreated();

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

                var addr = new Address("a", "a", 1, "a", "00223", "city", "state", currentLocation, 1, 2, 3);

                db.Addresses.Add(addr);

                db.SaveChanges();

            }

        }
    }

}
...