diff --git a/src/GlobalSuppressions.cs b/src/GlobalSuppressions.cs
index 394d0939..6a2ace70 100644
--- a/src/GlobalSuppressions.cs
+++ b/src/GlobalSuppressions.cs
@@ -49,6 +49,7 @@
[assembly: SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Scope = "namespace", Target = "Microsoft.Restier.Providers.EntityFramework")]
[assembly: SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Scope = "namespace", Target = "Microsoft.Restier.Providers.EntityFramework.Model")]
[assembly: SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Scope = "namespace", Target = "Microsoft.Restier.Providers.EntityFramework.Query")]
+[assembly: SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Scope = "namespace", Target = "Microsoft.Restier.Providers.EntityFramework.Spatial")]
[assembly: SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Scope = "namespace", Target = "Microsoft.Restier.Providers.EntityFramework.Submit")]
[assembly: SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Scope = "namespace", Target = "Microsoft.Restier.Publishers.OData")]
[assembly: SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Scope = "namespace", Target = "Microsoft.Restier.Publishers.OData.Batch")]
diff --git a/src/Microsoft.Restier.Providers.EntityFramework/Microsoft.Restier.Providers.EntityFramework.csproj b/src/Microsoft.Restier.Providers.EntityFramework/Microsoft.Restier.Providers.EntityFramework.csproj
index 15355fe2..906517f4 100644
--- a/src/Microsoft.Restier.Providers.EntityFramework/Microsoft.Restier.Providers.EntityFramework.csproj
+++ b/src/Microsoft.Restier.Providers.EntityFramework/Microsoft.Restier.Providers.EntityFramework.csproj
@@ -29,6 +29,10 @@
..\..\packages\Microsoft.OData.Edm.6.15.0\lib\portable-net45+win+wpa81\Microsoft.OData.Edm.dll
True
+
+ ..\..\packages\Microsoft.Spatial.6.15.0\lib\portable-net45+win+wpa81\Microsoft.Spatial.dll
+ True
+
@@ -77,6 +81,7 @@
Resources.resx
+
diff --git a/src/Microsoft.Restier.Providers.EntityFramework/Properties/Resources.Designer.cs b/src/Microsoft.Restier.Providers.EntityFramework/Properties/Resources.Designer.cs
index 6d1dc91f..27013733 100644
--- a/src/Microsoft.Restier.Providers.EntityFramework/Properties/Resources.Designer.cs
+++ b/src/Microsoft.Restier.Providers.EntityFramework/Properties/Resources.Designer.cs
@@ -69,6 +69,24 @@ internal static string DataModificationMustBeCUD {
}
}
+ ///
+ /// Looks up a localized string similar to Need 'LineString type', while input is {0}..
+ ///
+ internal static string InvalidLineStringGeographyType {
+ get {
+ return ResourceManager.GetString("InvalidLineStringGeographyType", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Need 'Point type', while input is {0}..
+ ///
+ internal static string InvalidPointGeographyType {
+ get {
+ return ResourceManager.GetString("InvalidPointGeographyType", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to The precondition check for request {0} on resource {1} is failed..
///
diff --git a/src/Microsoft.Restier.Providers.EntityFramework/Properties/Resources.resx b/src/Microsoft.Restier.Providers.EntityFramework/Properties/Resources.resx
index e49873a3..dd1d9dd8 100644
--- a/src/Microsoft.Restier.Providers.EntityFramework/Properties/Resources.resx
+++ b/src/Microsoft.Restier.Providers.EntityFramework/Properties/Resources.resx
@@ -120,6 +120,12 @@
A DataModificationEntry must be either New, Update or Delete.
+
+ Need 'LineString type', while input is {0}.
+
+
+ Need 'Point type', while input is {0}.
+
The precondition check for request {0} on resource {1} is failed.
diff --git a/src/Microsoft.Restier.Providers.EntityFramework/Spatial/GeographyConverter.cs b/src/Microsoft.Restier.Providers.EntityFramework/Spatial/GeographyConverter.cs
new file mode 100644
index 00000000..7033b123
--- /dev/null
+++ b/src/Microsoft.Restier.Providers.EntityFramework/Spatial/GeographyConverter.cs
@@ -0,0 +1,150 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+using System;
+using System.Data.Entity.Spatial;
+using System.Globalization;
+using System.Text;
+using Microsoft.Restier.Providers.EntityFramework.Properties;
+using Microsoft.Spatial;
+
+namespace Microsoft.Restier.Providers.EntityFramework.Spatial
+{
+ ///
+ /// The class defined conversion between GeographyPoint and DbGeography,
+ /// and between GeographyLineString and DbGeography.
+ ///
+ public static class GeographyConverter
+ {
+ private static readonly CultureInfo DefaultCulture = CultureInfo.GetCultureInfo("En-Us");
+ private const string GeographyTypeNamePoint = "Point";
+ private const string GeographyTypeNameLineString = "LineString";
+
+ public static GeographyPoint ToGeographyPoint(this DbGeography geography)
+ {
+ if (geography == null)
+ {
+ return null;
+ }
+
+ if (geography.SpatialTypeName != GeographyTypeNamePoint)
+ {
+ throw new InvalidOperationException(string.Format(
+ CultureInfo.InvariantCulture,
+ Resources.InvalidPointGeographyType,
+ geography.SpatialTypeName));
+ }
+
+ double lat = geography.Latitude ?? 0;
+ double lon = geography.Longitude ?? 0;
+ double? alt = geography.Elevation;
+ double? m = geography.Measure;
+ return GeographyPoint.Create(lat, lon, alt, m);
+ }
+
+ public static DbGeography ToDbGeography(this GeographyPoint point)
+ {
+ if (point == null)
+ {
+ return null;
+ }
+
+ string text = "POINT(" + point.Latitude.ToString(DefaultCulture) + " " +
+ point.Longitude.ToString(DefaultCulture);
+
+ if (point.Z.HasValue)
+ {
+ text += " " + point.Z.Value;
+ }
+
+ if (point.M.HasValue)
+ {
+ text += " " + point.M.Value;
+ }
+
+ text += ")";
+
+ return DbGeography.FromText(text);
+ }
+
+ public static GeographyLineString ToGeographyLineString(this DbGeography geography)
+ {
+ if (geography == null)
+ {
+ return null;
+ }
+
+ if (geography.SpatialTypeName != GeographyTypeNameLineString)
+ {
+ throw new InvalidOperationException(string.Format(
+ CultureInfo.InvariantCulture,
+ Resources.InvalidLineStringGeographyType,
+ geography.SpatialTypeName));
+ }
+
+ SpatialBuilder builder = SpatialBuilder.Create();
+ GeographyPipeline pipleLine = builder.GeographyPipeline;
+ pipleLine.SetCoordinateSystem(CoordinateSystem.DefaultGeography);
+ pipleLine.BeginGeography(SpatialType.LineString);
+
+ int numPoints = geography.PointCount ?? 0;
+ if (numPoints > 0)
+ {
+ DbGeography point = geography.PointAt(1);
+ pipleLine.BeginFigure(new GeographyPosition(point.Latitude ?? 0, point.Latitude ?? 0, point.Elevation, point.Measure));
+
+ for (int n = 2; n <= numPoints; n++)
+ {
+ point = geography.PointAt(n);
+ pipleLine.LineTo(new GeographyPosition(point.Latitude ?? 0, point.Latitude ?? 0, point.Elevation, point.Measure));
+ }
+
+ pipleLine.EndFigure();
+ }
+
+ pipleLine.EndGeography();
+ GeographyLineString lineString = (GeographyLineString)builder.ConstructedGeography;
+ return lineString;
+ }
+
+ public static DbGeography ToDbGeography(this GeographyLineString lineString)
+ {
+ if (lineString == null)
+ {
+ return null;
+ }
+
+ StringBuilder sb = new StringBuilder("LINESTRING(");
+ int n = 0;
+ foreach (var pt in lineString.Points)
+ {
+ double lat = pt.Latitude;
+ double lon = pt.Longitude;
+ double? alt = pt.Z;
+ double? m = pt.M;
+
+ string pointStr = lat.ToString(DefaultCulture) + " " + lon.ToString(DefaultCulture);
+
+ if (alt != null)
+ {
+ pointStr += " " + alt.Value;
+ }
+
+ if (m != null)
+ {
+ pointStr += " " + m.Value;
+ }
+
+ sb.Append(pointStr);
+ n++;
+ if (n != lineString.Points.Count)
+ {
+ sb.Append(",");
+ }
+ }
+ sb.Append(")");
+
+ return DbGeography.FromText(sb.ToString());
+ }
+ }
+}
diff --git a/src/Microsoft.Restier.Providers.EntityFramework/packages.config b/src/Microsoft.Restier.Providers.EntityFramework/packages.config
index 4578ec47..24c7de60 100644
--- a/src/Microsoft.Restier.Providers.EntityFramework/packages.config
+++ b/src/Microsoft.Restier.Providers.EntityFramework/packages.config
@@ -3,6 +3,7 @@
+
diff --git a/test/Microsoft.Restier.TestCommon/PublicApi.bsl b/test/Microsoft.Restier.TestCommon/PublicApi.bsl
index 91553af4..906f6b91 100644
--- a/test/Microsoft.Restier.TestCommon/PublicApi.bsl
+++ b/test/Microsoft.Restier.TestCommon/PublicApi.bsl
@@ -608,6 +608,31 @@ public class Microsoft.Restier.Publishers.OData.RestierPayloadValueConverter : M
public virtual object ConvertToPayloadValue (object value, Microsoft.OData.Edm.IEdmTypeReference edmTypeReference)
}
+[
+ExtensionAttribute(),
+]
+public sealed class Microsoft.Restier.Providers.EntityFramework.Spatial.GeographyConverter {
+ [
+ ExtensionAttribute(),
+ ]
+ public static DbGeography ToDbGeography (Microsoft.Spatial.GeographyLineString lineString)
+
+ [
+ ExtensionAttribute(),
+ ]
+ public static DbGeography ToDbGeography (Microsoft.Spatial.GeographyPoint point)
+
+ [
+ ExtensionAttribute(),
+ ]
+ public static Microsoft.Spatial.GeographyLineString ToGeographyLineString (DbGeography geography)
+
+ [
+ ExtensionAttribute(),
+ ]
+ public static Microsoft.Spatial.GeographyPoint ToGeographyPoint (DbGeography geography)
+}
+
public class Microsoft.Restier.Publishers.OData.Batch.RestierBatchChangeSetRequestItem : System.Web.OData.Batch.ChangeSetRequestItem, IDisposable {
public RestierBatchChangeSetRequestItem (System.Collections.Generic.IEnumerable`1[[System.Net.Http.HttpRequestMessage]] requests, System.Func`1[[Microsoft.Restier.Core.ApiBase]] apiFactory)