0

I am using SQL Server 2016, C# (.NET 5), and PetaPoco as my ORM.

I am getting the geography data from my data table by using the following in my SELECT clause:

CASE WHEN Jurisdiction.GeographicArea IS NULL THEN NULL ELSE Jurisdiction.GeographicArea.ToString() END AS GeographicArea

Before I send the data to the UI, I am massaging it to a Coordinate class by essentially stripping out anything that is not a number, decimal, whitespace, or comma. This is the Coordinate class:

[DebuggerDisplay("{Latitude},{Longitude}")]
public class Coordinate
{
    private float _latitude;
    private float _longitude;

    [JsonProperty("lat")]
    [JsonPropertyName("lat")]
    public float Latitude {
        get => _latitude;
        set {
            if (value < -90 || value > 90)
            {
                throw new ArgumentOutOfRangeException(nameof(Latitude), "The latitude is not between -90 and 90.");
            }
            _latitude = value;
        }
    }

    [JsonProperty("lng")]
    [JsonPropertyName("lng")]
    public float Longitude
    {
        get => _longitude;
        set
        {
            if (value < -180 || value > 180)
            {
                throw new ArgumentOutOfRangeException(nameof(Longitude), "The longitude is not between -180 and 180.");
            }
            _longitude = value;
        }
    }

    public Coordinate()
    {
        Latitude = 0;
        Longitude = 0;
    }

    public Coordinate(string latitude, string longitude)
    {
        if (!float.TryParse(latitude, out float latitudeFloat))
        {
            throw new ArgumentException("Latitude must be a valid number.");
        }

        if (!float.TryParse(longitude, out float longitudeFloat))
        {
            throw new ArgumentException("Longitude must be a valid number.");
        }
        Latitude = latitudeFloat;
        Longitude = longitudeFloat;
    }

    public Coordinate(float latitude, float longitude)
    {
        Latitude = latitude;
        Longitude = longitude;
    }
}

And this is the method that massages the data:

private readonly Regex _geographyIrrelevantData = new Regex(@"[^\d\.\s\-,]");
public IEnumerable<Coordinate> ConvertSqlGeographyToCoordinates(string geography)
{
    var geographyPoints = _geographyIrrelevantData.Replace(geography, string.Empty);
    geographyPoints = geographyPoints.Trim();

    var coordinateStrings = geographyPoints.Split(new[] { ',' });
    var coordinates = coordinateStrings.Select(coordinate =>
    {
        coordinate = coordinate.Trim();
        var points = coordinate.Split(new[] { ' ' });
        if (points.Count() != 2)
        {
            throw new Exception($"Coordinate is not in a valid format, expecting longitude and latitude separated by a space but got: {coordinate}");
        }

        // SQL represents points as: lng lat
        // bubble up invalid values from property setter
        return new Coordinate(points[1], points[0]);
    });

    return coordinates;
}

Ultimately what happens with the data is that it creates a polygon on a (Google) map.

This approach works phenomenally when the SQL value only represents one shape, e.g. one polygon. However, because this data typically represents parishes (aka - counties outside of Louisiana) I am running into an issue where some parishes have multiple shapes (e.g. a body of water splits the parish in half). What is happening is that my method is returning a single collection of Coordinates when it reality, production data could have multiple collections of Coordinates.

Before I started the process of manually trying to parse this data, I wanted to ask: is there a better/easier approach to what I am doing?

David
  • 5,877
  • 3
  • 23
  • 40
  • Use [`.STAsText()`](https://learn.microsoft.com/en-us/sql/t-sql/spatial-geography/stastext-geography-data-type?view=sql-server-ver15) to convert the geography column to text - you can then parse it to find the individual polygons. You'll probably find that your County objects are represented as a [MULTIPOLYGON](https://learn.microsoft.com/en-us/sql/relational-databases/spatial/multipolygon?view=sql-server-ver15) – Mr. T May 18 '22 at 19:35
  • @Mr.T - They are. This is why I can easily parse single collections by stripping out just about everything in the RegEx. I understand I can stop stripping out the parenthesis and parse the SQLGeography values in more detail, I just wanted to make sure that there wasn't something a bit easier before I started down that road. – David May 18 '22 at 19:57

0 Answers0