Efcore: Cosmos: Spatial types, functions and spatial indexes

Created on 21 Aug 2019  路  11Comments  路  Source: dotnet/efcore

Use GeoJSON which supports point, polygon and linestring

area-cosmos area-spatial type-enhancement

All 11 comments

I was super stoked to use EF Core with dotnet 3 - but I've run into an issue with GeoJSON and the Cosmos DB database.

The GeoJSON spec says that coordinates must be stored as follows:

{
"type": "Point",
"coordinates": [125.6, 10.1]
}

So I created a C# POCO class like so:

public class GeoLocation
    {
        [JsonProperty("type")]
        public string Type { get; set; }
        [JsonProperty("coordinates")]
        public double[] Coordinates { get; set; }
    }

However using this with EF Core + Cosmos throws the following:

Exception has occurred: CLR/System.InvalidOperationException
Exception thrown: 'System.InvalidOperationException' in System.Private.CoreLib.dll: 'The property 'GeoLocation.Coordinates' could not be mapped, because it is of type 'double[]' 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'.'
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.ValidatePropertyMapping(IModel model, IDiagnosticsLogger`1 logger)
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.Validate(IModel model, IDiagnosticsLogger`1 logger)
   at Microsoft.EntityFrameworkCore.Cosmos.Internal.CosmosModelValidator.Validate(IModel model, IDiagnosticsLogger`1 logger)

The biggest pain point for us is that Azure Search requires that coordinates be serialised as GEOJson, which is just not possible when using EF Core.

In conclusion, it is not possible to use Cosmos, EF Core, and Azure Search with Geo Spacial data :(

@AndriySvyryd Any easy workarounds using NetTopologySuite.IO.GeoJSON?

var geoJsonString = new GeoJsonWriter().Write(point);
var point = new GeoJsonReader().Read<Point>(geoJsonString);

Yes, setting up value converters should be enough to get basic functionality.

@xtellurian Does it have to be embedded JSON or will it work as a string containing JSON?

@AndriySvyryd Do we automatically embed JObject properties?

var jObject = new JObject();
new GeoJsonWriter().Write(point, new JTokenWriter(jObject));

var point = new GeoJsonReader().Read<Point>(new JTokenReader(jObject));

We don't have any special handling for JObject, but string should work, I'll try it out later

Thanks for jumping on this to help :)

@bricelam
I tried manually serializing the GeoJSON in CosmosDB and indexing with Azure Search (as below), and the search indexer seems like it works!

{
"GeoLocation": "{ \"type\": \"Point\", \"coordinates\": [100.2093,-15.868]}"
}

@AndriySvyryd
It sounds like I can use value conversions to serialize/deserialize the GEOJson with the EF CosmosDB provider.

I don't see a need to use NetTopologySuite.IO.GeoJSON ...

lol, using NTS just to serialize points is definitely overkill. It鈥檒l come in handy for more complex spatial scenarios though

The problem with the solution above is that the whole GeoLocation object is actually saved as a string instead of a JSON literal. This means that Cosmos Indexing won't work. Is there a way to use a value converter but the force EF Core to use the converted value verbatim?

It should be saved as

{
    "GeoLocation": {
        "type": "Point", 
        "coordinates": [100.2093,-15.868]
    }
}

@cwoolum You'd be able to do it when https://github.com/dotnet/efcore/issues/20584 is implemented.
For now you can modify the underlying JObject directly

In the short term, I think that by utilizing that with a raw sql command, you could feasibly use ST_DISTANCE querying using EF Core and Cosmos.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

bgribaudo picture bgribaudo  路  3Comments

miguelhrocha picture miguelhrocha  路  3Comments

mohsin91 picture mohsin91  路  3Comments

ryanwinter picture ryanwinter  路  3Comments

spottedmahn picture spottedmahn  路  3Comments