Banyak developer sejak rilis SQL 2008, meminta agar tipe Spatial Data support untuk Entity Framework. Itu adalah mimpi bagi pengguna Microsoft ORM untuk membuat aplikasi bisnis NET cepat dengan menggunakan Spatial Data. Pada bulan Mei 2012 rilis Entity Framework 5 (EF5). Telah berhasil meningkatkan kinerja jika dibandingkan dengan versi Entity Framework sebelumnya dan juga memiliki dukungan untuk jenis spasial. Fungsi spasial dalam EF5 membutuhkan NET 4.5.
Fungsi spasial dalam EF5 membutuhkan NET 4.5. Ini berarti kita perlu menginstall Visual Studios 2012. Anda dapat men-download VS 2012 di sini: http://www.microsoft.com/visualstudio/en-us
Data Spasial di Entity Framework
Dalam Entity Framework 5, Microsoft memperkenalkan DbGeometry dan DbGeography jenis baru. Jenis ini menyediakan perubahan lokasi dan banyak fungsi untuk memanipulasi poin spasial menggunakan fungsi geometri yang pada gilirannya dapat digunakan untuk melakukan query spasial umum.
Jenis DbGeography / DbGeometry yang berubah, yang berarti bahwa kita tidak dapat merubah setelah jenis tersebut dibuat. Kita perlu menggunakan metode khusus untuk meng-instantiate jenis ini. Jenis ini tidak memiliki constructor () dan kita tidak dapat menetapkan sifat seperti Latitude dan Longitude.
Hal ini penting untuk disampaikan bahwa jenis ini didefinisikan ke dalam System.Data.Entity yang dibuat di System.Data.Spatial namespace. Sekarang kita mungkin menggunakan SqlGeometry dan jenis SqlGeography, didefinisikan dalam Microsoft.SqlServer.Types namespace.
Misalnya Entity dengan nama “world” berisi properti geom jenis DbGeometry.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=true)] [DataMemberAttribute()] public global::System.Data.Spatial.DbGeometry geom { get { return _geom; } set { OngeomChanging(value); ReportPropertyChanging("geom"); _geom = StructuralObject.SetValidValue(value, true, "geom"); ReportPropertyChanged("geom"); OngeomChanged(); } } private global::System.Data.Spatial.DbGeometry _geom; partial void OngeomChanging(global::System.Data.Spatial.DbGeometry value); partial void OngeomChanged(); |
1 2 3 4 5 6 7 8 |
#region DashboardJs public ActionResult DashboardJs() { ViewBag.Message = "Spatial Data Dashboard"; return View(); } #endregion //DashboardJs |
Bila kita memiliki data dari jenis DbGeometry / DbGeography. Ada dua pilihan:
Untuk mengkonversi tipe Spatial Data untuk WKT (Well Known Text) dan mengirimkannya ke klien sebagai bagian dari JSON atau XML
Kita harus memiliki metode hasil yang berlanjut untuk JSON
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
#region CountryByName [OutputCache(VaryByParam = "countryName", Duration = 120)] public JsonResult CountryByName(string countryName) { switch (countryName) { case "UK": countryName = "United Kingdom"; break; case "USA": countryName = "United States"; break; } var results = spDemo.worlds.Where(x => x.CNTRY_NAME == countryName); List<CountryInfo> ret = new List<CountryInfo>(); foreach (world country in results) { CountryInfo info = new CountryInfo { Id = country.ID, Code = country.CODE, CountryName = country.CNTRY_NAME, Population = country.POP_CNTRY, Extend = GetGeometryBoundary(country) }; ret.Add(info); } var retVal = Json(ret, JsonRequestBehavior.AllowGet); return retVal; } #endregion //CountryByName |
Kita harus menggunakan juga beberapa metode pembantu untuk mendapatkan daftar poin, yang mewakili sebuah data dari contoh DbGeometry. Jangan lupa bahwa titik indeks DbGeometry / DbGeography mulai dari 1!.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#region GetGeometryBoundary public static SpatialRect GetGeometryBoundary(world country) { List<SpatialPoint> multiPoints = new List<SpatialPoint>(); var numPoints = country.geom.Envelope.ElementAt(1).PointCount; for (int i = 1; i <= numPoints; i++) { SpatialPoint pnt = new SpatialPoint((double)( country.geom.Envelope.ElementAt(1).PointAt(i).XCoordinate), (double)(country.geom.Envelope.ElementAt(1).PointAt(i).YCoordinate)); multiPoints.Add(pnt); } SpatialRect rect = multiPoints.GetBounds(); return rect; } #endregion //GetGeometryBoundary |
1 2 3 4 5 6 7 8 9 10 11 |
#region CountryInfo public class CountryInfo { public int Id { get; set; } public string Code { get; set; } public string CountryName { get; set; } public long? Population { get; set; } public SpatialRect Extend { get; set; } } #endregion //CountryInfo |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#region SpatialPoint public class SpatialPoint { public SpatialPoint(double x, double y) { this.X = x; this.Y = y; } public double X { get; set; } public double Y { get; set; } } #endregion //SpatialPoint |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#region SpatialRect public struct SpatialRect { public SpatialRect(double pLeft, double pTop, double pWidth, double pHeight) { left = pLeft; top = pTop; width = pWidth; height = pHeight; } public double left; public double top; public double width; public double height; } #endregion //SpatialRect |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
#region Extensions public static class Extensions { #region GetBounds public static SpatialRect GetBounds(this IList<SpatialPoint> points) { double xmin = Double.PositiveInfinity; double ymin = Double.PositiveInfinity; double xmax = Double.NegativeInfinity; double ymax = Double.NegativeInfinity; SpatialPoint p; for (var i = 0; i < points.Count; i++) { p = points[i]; xmin = Math.Min(xmin, p.X); ymin = Math.Min(ymin, p.Y); xmax = Math.Max(xmax, p.X); ymax = Math.Max(ymax, p.Y); } if (Double.IsInfinity(xmin) || Double.IsInfinity(ymin) || Double.IsInfinity(ymin) || Double.IsInfinity(ymax)) { return new SpatialRect(0.0, 0.0, 0.0, 0.0); } return new SpatialRect(xmin, ymin, xmax - xmin, ymax - ymin); } #endregion //GetBounds } #endregion //Extensions |