question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Implement SqlGeography and SqlGeometry for Spatial Types support for .Net Core

See original GitHub issue

Cannot run Microsoft.SqlServer.Types because \Microsoft.SqlServer.Server\IBinarySerialize.cs is missing in System.Data.

Since no source code is available, and contact owners on nuget yields a HTTP-500, I’m opening an issue here. I’d like to compute a polygon union…

#if false
namespace AnySqlWebAdmin
{
    public class GeoPoint
    {
        public decimal Lat;
        public decimal Long;
        public GeoPoint(decimal latitude, decimal longitude)
        {
            this.Lat = latitude;
            this.Long = longitude;
        }
        public GeoPoint() : this(0,0) { }
        public override string ToString()
        {
            return this.Lat.ToString(System.Globalization.CultureInfo.InvariantCulture)
                + " "
                + this.Long.ToString(System.Globalization.CultureInfo.InvariantCulture);
        }
    }
    public class GeographicOperations 
    {
        public static string ObjJoin(string separator, params object[] objs)
        {
            string result = null;
            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            
            bool isNotFirst = false;
            
            for (int i = 0; i < objs.Length; ++i)
            {
                if (objs[i] == null)
                    continue;
                if (separator != null && isNotFirst)
                {
                    sb.Append(separator);
                }
                else
                    isNotFirst = true;
                
                if(objs[i] != null)
                    sb.Append(objs[i].ToString());
            }
            
            result = sb.ToString();
            sb.Clear();
            sb = null;
            
            return result;
        }
        // geography::STPolyFromText('POLYGON((9.3763619 47.4330074,9.3764389 47.4329684,9.3764072 47.4329405,9.3763969 47.4329322,9.3759864 47.4326004,9.376056 47.4325644,9.3761349 47.4325167,9.37619 47.4325653,9.376312 47.4326732,9.3765907 47.4328683,9.3766389 47.4328521,9.3767794 47.4329452,9.3764748 47.4331106,9.3763619 47.4330074))', 4326)
        // geography::STPolyFromText('POLYGON((9.3766833 47.4319973,9.3772045 47.4324131,9.3771257 47.432459,9.3769959 47.4323535,9.3767225 47.4325076,9.3768938 47.432637,9.3769843 47.4325975,9.3772713 47.432826,9.3771862 47.4328789,9.376941 47.4326789,9.3767283 47.4327757,9.3765053 47.4325749,9.376312 47.4326732,9.37619 47.4325653,9.3761349 47.4325167,9.376056 47.4325644,9.3757946 47.43237,9.3760399 47.4322419,9.376144 47.4323272,9.3761809 47.4323125,9.3762975 47.432428,9.3762371 47.4324602,9.3763095 47.4325246,9.3764699 47.4324328,9.3763633 47.4323437,9.3763976 47.4323193,9.3763247 47.4322628,9.3763972 47.4322251,9.3764363 47.4322061,9.3766528 47.4323718,9.3768611 47.4322514,9.3765976 47.4320409,9.3766833 47.4319973))', 4326)
        
        public static Microsoft.SqlServer.Types.SqlGeography ToPolygon(string text)
        {
            // text = @"POLYGON((-122.358 47.653, -122.348 47.649, -122.348 47.658, -122.358 47.658, -122.358 47.653))";
            System.Data.SqlTypes.SqlChars polygon = new System.Data.SqlTypes.SqlChars(new System.Data.SqlTypes.SqlString(text));
            Microsoft.SqlServer.Types.SqlGeography poly = Microsoft.SqlServer.Types.SqlGeography.STMPolyFromText(polygon, 4326);
            return poly;
        }
        
        public static Microsoft.SqlServer.Types.SqlGeography ToPolygon(GeoPoint[] points)
        {
            string pointText = ObjJoin(", ", points);
            string text = "POLYGON((" + pointText + "))";

            Microsoft.SqlServer.Types.SqlGeography poly = ToPolygon(text);
            return poly;
        }
        
        public static void Test()
        {
            // DECLARE @Geom TABLE ( shape geometry ); 
            // SELECT geometry::UnionAggregate(shape).ToString() FROM @Geom;
            // geometry ST_Union(geometry[] g1_array);
            // https://docs.microsoft.com/en-us/sql/t-sql/spatial-geometry/unionaggregate-geometry-data-type?view=sql-server-2017
            // https://gis.stackexchange.com/questions/237644/what-does-the-st-union-of-the-geometry-column-of-two-tables-produce

            GeoPoint[] points = new GeoPoint[]
            {
                  new GeoPoint(0,0)
                , new GeoPoint(0,0)
                , new GeoPoint(0,0)
                , new GeoPoint(0,0)
                , new GeoPoint(0,0)
            };

            string s1 = "POLYGON((9.3763619 47.4330074,9.3764389 47.4329684,9.3764072 47.4329405,9.3763969 47.4329322,9.3759864 47.4326004,9.376056 47.4325644,9.3761349 47.4325167,9.37619 47.4325653,9.376312 47.4326732,9.3765907 47.4328683,9.3766389 47.4328521,9.3767794 47.4329452,9.3764748 47.4331106,9.3763619 47.4330074))";
            string s2 = "POLYGON((9.3766833 47.4319973,9.3772045 47.4324131,9.3771257 47.432459,9.3769959 47.4323535,9.3767225 47.4325076,9.3768938 47.432637,9.3769843 47.4325975,9.3772713 47.432826,9.3771862 47.4328789,9.376941 47.4326789,9.3767283 47.4327757,9.3765053 47.4325749,9.376312 47.4326732,9.37619 47.4325653,9.3761349 47.4325167,9.376056 47.4325644,9.3757946 47.43237,9.3760399 47.4322419,9.376144 47.4323272,9.3761809 47.4323125,9.3762975 47.432428,9.3762371 47.4324602,9.3763095 47.4325246,9.3764699 47.4324328,9.3763633 47.4323437,9.3763976 47.4323193,9.3763247 47.4322628,9.3763972 47.4322251,9.3764363 47.4322061,9.3766528 47.4323718,9.3768611 47.4322514,9.3765976 47.4320409,9.3766833 47.4319973))'";

            // ST_GeomFromText(text WKT, integer srid);
            // ST_Union, ST_AsText
            // ST_GeomFromText('POINT(-2 3)') ) )
            // ST_Intersects( geography geogA , geography geogB )

            // Could not load Microsoft.SqlServer.Server

            Microsoft.SqlServer.Types.SqlGeography poly1 = ToPolygon(s1); // points);
            Microsoft.SqlServer.Types.SqlGeography poly2 = ToPolygon(s2); // points);

            Microsoft.SqlServer.Types.SqlGeography poly3 = poly1.STUnion(poly2);
            System.Data.SqlTypes.SqlChars chars = poly3.STAsText();
            string value = new string(chars.Value);
            System.Console.WriteLine(value);
        }
    }
}
#endif

And while you are at it, the version for the full .NET framwork (core also) should also work if SQL-Server is not installed on the machine that Microsoft.SqlServer.Types is executed on…

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Reactions:23
  • Comments:68 (13 by maintainers)

github_iconTop GitHub Comments

14reactions
dotMortencommented, Feb 1, 2023

Is this actually complete? Last I checked this only works on x86 and x64 Windows, which isn’t in the spirit of claiming .net core support. With .NET 6 running on mac, linux, ios and android, there’s not really much benefit to this work until we have a proper crossplatform solution.

The nuget package explorer confirms it too with only runtimes supplied for 2 of the 3 Windows architectures and none for anything else: image

It is in fact rather weird that the library claims to be netstandard2.1 instead of net5.0-windows which is what it really is.

8reactions
dotMortencommented, Feb 1, 2019

@dotMorten has created a version of the Microsoft.SqlServer.Types library that works on .NET Core, but my understanding is that it does not implement spatial calculations.

That is correct. While I could probably implement most of the calculations, the results are going to be slightly off. I don’t think that’s a good idea (for now perform those calculations server-side as part of your query). I’d rather we can get the native part of the spatial types open-sourced, so we can recompile it for more platforms (that would be a lot less work than porting it to C#).

Read more comments on GitHub >

github_iconTop Results From Across the Web

Future of Microsoft.SqlServer.Types in .NET Core or .NET 6
SqlServer.Types full framework to a more scalable solution using .NET Core has proven to be difficult. Net Topology Suite does not use geography ......
Read more >
Geography SQL type support in .NET Core 6 / Entity ...
According to this video here when creating the model in Entity Framework, the data type to use is Geometry (even for a Geography...
Read more >
dotMorten.Microsoft.SqlServer.Types 2.5.0
Allows you to use SQL Server spatial SqlHierarchy types on a machine without SQL Server installed and decode these UDT types in any...
Read more >
Brief Intro To Netopology in .NET Core | by Aizeem Paroya
NET Core app?” and from there started going down some disappointing rabbit holes to find that SQL geography isn't supported yet in .NET...
Read more >
work with spatial types
How to work with spatial types. The LLBLGen Pro designer supports spatial types on SQL Server and PostgreSQL, using both database first and...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found