Search code examples
entity-frameworkentity-framework-coreopenlayers

Entity Framework CRUD operations with Openlayers Geometry object


I am using Openlayers and trying to save the geometry information in my DB.

When i draw a polygon on openlayers map, the object(feature) generated is in this format

{
 "type": "Polygon",
    "coordinates": [
      [
        [
          54.86572265625,
          74.0013854318592
        ],
        [
          53.59130859375,
          73.62159408606237
        ],
        [
          53.96484375,
          73.16953636227885
        ],
        [
          55.986328125,
          73.59679245247814
        ]
      ]
    ]
  }

Above object has 2 properties. {type: string, coordinates: someNestedArray}

I am passing this object to my API to save it in DB. But am facing issue with defining type of coordinates property.

Basically it is of type float[][][] so i created my EF model class as below

public class Geometry
  {
     public string Type { get; set; }

     public float[][][] Coordinates { get; set; }
  }

when i try to get/update, EF is throwing below error

{"The property 'Geometry.Coordinates' could not be mapped, because it is of type 'float[][][]'
 which is not a supported primitive type or a valid entity type. Either explicitly map this property, 
or ignore it using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'."}

the error is clear. EF cannot map these un-supported types on its own. How can i define a mapping explicitly ? Or is there any way i can make it work ? is the type float[][][] correct ?

Thanks in advance.


Solution

  • You can always save coordinates as string where coordinates are separated by comma.

    For instance in FE part you can handle it like this:

            const someLine =  feature.getGeometry().transform("EPSG:4326", 
                            "EPSG:3857");
       
            const geometryLine = someLine
              .clone()
              .getGeometry()
              .transform("EPSG:3857", "EPSG:4326");
    
            const geometryCoords = geometryLine.getCoordinates().join(";");
    

    Then you will get something like this: "43.520548594674132,26.565803087473146;...." which can be saved to database as a string. (it can be additionally tweaked with fewer decimal points, etc..)

    After that, if you want to handle/fetch data through API and map it via automapper(or some custom implementation)to List of Coordinates (for example something like this)

     public class Coordinates
        {
            public double Longitude { get; set; }
            public double Latitude { get; set; }
        }
    

    To map previously saved data to DTO you can use something like this

     public class GeneralProfile : Profile
       {
            public GeneralProfile()
            {
                CreateMap<Route, GetSavedRouteDTO>()
                    .ForMember(x => x.TripLength, options => options.MapFrom(x => x.Length))
                    .ForMember(x => x.RouteCoordinates, options => options.MapFrom(MapFromStringCoordinates));
                CreateMap<Route, RouteCreateDTO>().ReverseMap();
            }
    
    
            private List<Coordinates> MapFromStringCoordinates(Route route, GetSavedRouteDTO getSavedRouteDTO)
            {
    
                var currentCulture = System.Globalization.CultureInfo.InstalledUICulture;
                var numberFormat = (System.Globalization.NumberFormatInfo)currentCulture.NumberFormat.Clone();
                numberFormat.NumberDecimalSeparator = ".";
    
                var coordinates = new List<Coordinates>();
                var coordinatesSplit = route.Coordinates.Split(";");
    
                foreach (var coord in coordinatesSplit)
                {
                    var currentCoord = coord.Split(","); 
                    if (currentCoord.Length > 1)
                    {
                        var latitude = double.Parse(currentCoord[0], numberFormat);
                        var longitude = double.Parse(currentCoord[1], numberFormat);
                        var coords= new Coordinates { Latitude = latitude, Longitude = longitude };
    
                        coordinates.Add(coords);
                    }
                }
    
                return coordinates;
            }
        } 
    

    With that you ll get the list of coordinates that will contain latitude and longitude and from which will you create geometry entity.