43

I want to construct a DbGeography point from latitude and longitude doubles.

I know I can convert my doubles to strings and use the DbGeography.FromText method.

var latitude = 50.0d;
var longitude = 30.0d;

var pointString = string.Format(
    "POINT({0} {1})",
    longitude.ToString(),
    latitude.ToString());

var point = DbGeography.FromText(pointString);

But it seems wasteful to convert my doubles to strings just so that DbGeography can parse them as doubles again.


I tried constructing a DbGeography directly like this:

var point = new DbGeography()
{
    Latitude = 50,
    Longitude = 30
};

but the Latitude and Longitude properties are read-only. (Which makes sense, because the DbGeography class handles much more than individual points)


The DbGeography class also provides a FromBinary method that takes a byte array. I'm not sure how to martial my latitude and longitude doubles into a correctly-formatted byte array.

Is there a simpler way to construct a DbGeography instance out of Latitude and Longitude doubles than the code at the top?

jcarpenter2
  • 5,312
  • 4
  • 22
  • 49
  • 1
    Why don't you create a method `public static DbGeography CreatePoint(double, double)` which would wrap your code ? It won't avoid conversion, but at least makes your code clearer... – Raphaël Althaus Apr 16 '14 at 14:00
  • I'll probably end up doing something like that. It's too bad there aren't static extension methods; I would like to be able to keep all of the static `DbGeography` create methods under one class. – jcarpenter2 Apr 16 '14 at 14:09
  • 2
    Not that this really helps, but in the version 6+ of C# you can use string interpolation like this: DbGeography.FromText($"POINT({longitude} {latitude})"); – Martin Brown May 31 '16 at 15:45

4 Answers4

55

In short, no there isn't.

SqlGeography has an appropriate method:

Microsoft.SqlServer.Types.SqlGeography.Point(latitude, longitude, srid);

... but you would then have to convert to DbGeography anyway. If you are interested in this, see a previous answer of mine on converting: DbGeography to SqlGeography (and back)

That said, I completely agree with Raphael Althaus in that you should create a static method to make your life easier:

public static DbGeography CreatePoint(double lat, double lon, int srid = 4326)
{
    string wkt = String.Format("POINT({0} {1})", lon, lat);

    return DbGeography.PointFromText(wkt, srid);
}

Then all usage can go through that method.

EDIT

@Korayem Made an excellent suggestion that I actually have done myself since originally answering the question. Most people use the SRID 4326 so we can make the static method easier to use by carrying that as the parameter's default value.

Community
  • 1
  • 1
Jon Bellamy
  • 3,333
  • 20
  • 23
  • 3
    Useful *GeoUtils* class that contains CreatePoint method can be found here: http://codepaste.net/73hssg – Zharro Mar 12 '15 at 07:33
  • @Zharro Whilst not hard to modify to suit user needs, the example above also allows a dynamic SRID value whereas GeoUtils assumes 4326. Some people require a different SRID (and could simply change the number) but some people work with multiple SRID's and having the ability to specify it within the method parameters allows for this. – Jon Bellamy Mar 12 '15 at 08:57
  • @JonBellamy @Zharro doing this gives best of two worlds `public static DbGeography CreatePoint(double lat, double lon, int srid=4326)` – Korayem May 11 '16 at 09:39
  • @Korayem You are right, I actually do that myself. I'll update the answer for everyone's benefit. – Jon Bellamy May 13 '16 at 07:39
  • Hello. In my scenario I want to store simple latitude and longitude values. Should I bother storing with EF using DbGeography or create a simple complex-type? What's the advantage of using `DbGeography`? – Shimmy Weitzhandler Feb 13 '17 at 03:11
  • 1
    @Shimmy The benefit comes from when you want to use spatial functions (such as nearest location etc.). If you're not doing any of this, there isn't really a benefit. You could create a complex type, but if you're doing that you may as well use DbGeography (SqlGeography), so just make two columns. – Jon Bellamy Feb 13 '17 at 11:10
  • @JonBellamy Thank you! – Shimmy Weitzhandler Feb 14 '17 at 07:26
  • 1
    I would also suggest changing the answer to always use CultureInfo.InvariantCulture. In my culture comma is a decimal separator and so this code didn't work right away. – FiDO May 11 '17 at 10:05
0

You can simplify it like this:

  DbGeography.FromText(String.Format(CultureInfo.InvariantCulture, "POINT({0} {1})", longitude, latitude));

for example:

DbGeography.FromText("POINT(-73.935242 40.730610)"),

without using int srid = 4326; which is default value.

If you use it many times use it in a static method:

private static DbGeography CreatePoint(double latitude, double longitude)
{
    return DbGeography.FromText(String.Format(CultureInfo.InvariantCulture, "POINT({0} {1})", longitude, latitude));
}

PS: Don't forget to use CultureInfo.InvariantCulture because you will get an exception for some cultures.

Dan
  • 448
  • 10
  • 20
0

Assuming you are targeting SQL Server, you can do it without string parsing. First create a SqlGeography:

var sqlPoint = Microsoft.SqlServer.Types.SqlGeography.Point(latitude, longitude, srid);

Then create a DbGeography from this SqlGeography (see my answer to a separate question about DbGeography conversion).

var dbPoint = System.Data.Entity.SqlServer.SqlSpatialServices.Default.GeographyFromProviderValue(sqlPoint);
Mark Glasgow
  • 529
  • 2
  • 9
0

you can do it by using SqlGeographyBuilder

                SqlGeographyBuilder sqlGeographyBuilder = new SqlGeographyBuilder();
                sqlGeographyBuilder.SetSrid(4326);
                sqlGeographyBuilder.BeginGeography(OpenGisGeographyType.Polygon);
                sqlGeographyBuilder.BeginFigure(37.944197500754 ,- 127.24365234375);
                sqlGeographyBuilder.AddLine(37.944197500754 ,- 80.68359375);
                sqlGeographyBuilder.AddLine(24.966140159913 ,- 80.68359375);
                sqlGeographyBuilder.AddLine(24.966140159913 ,- 127.24365234375);
                sqlGeographyBuilder.AddLine(37.944197500754 ,- 127.24365234375);
                sqlGeographyBuilder.EndFigure();
                sqlGeographyBuilder.EndGeography();

                SqlGeography polygon = sqlGeographyBuilder.ConstructedGeography;
Abdullah Tahan
  • 1,963
  • 17
  • 28