コンテンツへスキップ
SQL Server を使用した ASP.Net MVC での空間データの使用

SQL Server を使用した ASP.Net MVC での空間データの使用

Entity Framework 5 で待望されている機能の 1 つは、空間サポートです。

7min read

コードプロジェクトSQL 2008 のリリース以来、多くの開発者が Entity Framework での空間データ型のサポートを求めてきました。Microsoft ORM のユーザーにとって、空間データを使用して .NET ビジネス アプリケーションを迅速に作成することは夢でした。 今年の 5 月に、Entity Framework 5 (EF5) のリリース候補が発表されました。このバージョンは、以前の EF バージョンと比較してパフォーマンスが向上しており、空間型もサポートされています。EF5 の空間機能には .NET 4.5 が必要です。

EF5 の空間機能には .NET 4.5 が必要です。これは、Visual Studios 2012 がインストールされている必要があることを意味します。VS 2012 のリリース候補は、こちらからダウンロードできますhttp://www.microsoft.com/visualstudio/en-us

Entity Framework の空間データ

Entity Framework 5.0 より前の .NET 4.5 では、上記のデータを使用するには、ストアド プロシージャまたは生の SQL コマンドを使用して空間データにアクセスする必要がありました。ただし、Entity Framework 5 では、Microsoft は新しいDbGeometry型とDbGeography型を導入しました。これらの不変の位置の種類は、ジオメトリ関数を使用して空間ポイントを操作するための一連の機能を提供します。ジオメトリ関数を使用すると、上記の SQL 構文で説明したような一般的な空間クエリを実行できます。

DbGeography/DbGeometry 型は不変であるため、一度作成すると書き込むことはできません。それらは、インスタンス化するためにファクトリメソッドを使用する必要があるという点で少し奇妙です - constructor()はなく、LatitudeやLongitudeのようなプロパティに割り当てることはできません。

これらの型は、System.Data.Spatial名前空間の System.Data.Entity アセンブリで定義されていることに注意してください。ここまでで、Microsoft.SqlServer.Types名前空間で定義されているSqlGeometry型とSqlGeography型を使用したことがあるでしょう

空間データを使用したモデルの作成

まず、サンプル データベースNorthwindSpatialDemoのエンティティを含む単純な Entity Framework モデルを作成しましょう。world という名前のエンティティには、DbGeometry型の geom プロパティが含まれています。サンプルは SQL Server 2012 を使用していますが、SQL Server 2008 で実行することもできます。

[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();

Northwind エンティティ

空間データを含むサンプル SpatialDemo データベース。テーブル ワールドは、"geom" という名前の Geometry タイプからファイルされます。このフィールドには、国のコンターがポリゴンとして含まれます

SpatialDemo データベースから生成されたエンティティ ワールドには、ジオメトリ タイプのフィールド "geom" が含まれています。

ASP.Net MVC 4 アプリケーションと Entity Framework 5 RC および Spatial データ

今では、ASP.Net MVCアプリケーションで空間データを使用するのは非常に簡単になりました。

  • Controller

Controller は、Infragistics jQuery コントロールを含むダッシュボードを含むビューを返します。

#region DashboardJs
public ActionResult DashboardJs()
{
    ViewBag.Message = "Spatial Data Dashboard"; 
    return View();
}
#endregion //DashboardJs
  • Spatial Data Maintenance

DbGeometry / DbGeographyタイプのデータがある場合、シリアル化することはできません。次の 2 つのオプションがあります。

  • 空間データ型を WKT (Well Known Text) に変換し、JSON または XML の一部としてクライアント (ビュー) に送信するには
  • シリアル化できる独自のクラスを使用するには

このサンプルは、2 番目の方法を示しています

CountryByNameメソッドは、結果をJSONにシリアル化して、ビューで使用できるようにします

#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 ret = new List();
   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

GetGeometryBoundaryは、DbGeometry インスタンスのエンベロープを表すポイントの一覧を取得するために使用されるヘルパー メソッドです。DbGeometry/DbGeography ポイント インデックスは 1 から始まります。

#region GetGeometryBoundary
public static SpatialRect GetGeometryBoundary(world country)
{
    List multiPoints = new List();
    var numPoints = country.geom.Envelope.ElementAt(1).PointCount;
    for (int i = 1; i <= numpoints="" i="" pre="">
    {
        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

ContryInfoは、データをシリアル化するために使用されるヘルパー クラスです

#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

SpatialPointは、ポイントデータを保持するためのヘルパークラスです。次のものを使用できます。

#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

SpatialRectは、国を広げ続けるためのヘルパー クラスです

#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

GetBoundsは、ポイントのリストの境界を取得するために使用される拡張メソッドです。

#region Extensions
public static class Extensions
{
    #region GetBounds
    public static SpatialRect GetBounds(this IList 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

眺める

このビューには、Infragistics jQuery Grid、Chart、Map のダッシュボードが表示されます。

このサンプルで最も重要な部分は、空間データ (この場合は国拡張) を返すコントローラーのメソッドをクエリする方法です。

var countryUrl = "/Home/CountryByName?countryName=" + args.row.element[0].cells[1].textContent
 
...
 
$.getJSON(countryUrl,
  function (json, text) {
      $.each(json, function (index, value) {
         var country = value;
         var extend = country["Extend"];
         var zoom = $("#map").igMap("getZoomFromGeographic", extend);
         $("#map").igMap("option", "windowRect", zoom);
      });
 });

Infragistics jQuery Map instance definition.

$("#map").igMap({
     width: "500px",
     height: "500px",
     panModifier: "control",
     horizontalZoomable: true,
     verticalZoomable: true,
     windowResponse: "immediate",
     overviewPlusDetailPaneVisibility: "visible",
     seriesMouseLeftButtonUp: function (ui, args) {
     var tets = args;
    }
});

Infragistics jQuery Gridは、選択した顧客の国をズームします。

$('#grid').igGrid({
     virtualization: false, height: 280, width: 650,
     dataSource: "/Home/Customers",
     autoGenerateColumns: false,
     columns: [
        { headerText: "Customer ID", key: "CustomerID", width: "120px", dataType: "string" },
        { headerText: "Country", key: "Country", width: "150px", dataType: "string" },
        { headerText: "City", key: "City", dataType: "string" },
        { headerText: "Contact Name", key: "ContactName", dataType: "string" },
        {headerText: "Phone", key: "Phone", dataType: "string" }
     ],
     features: 
     [{
       name: 'Selection',
       mode: 'row',
       multipleSelection: false,
       rowSelectionChanged: function (ui, args) {
       $("#chart").igDataChart({
          dataSource: "/Home/Orders?userID=" + args.row.element[0].cells[0].textContent
       });

       selected = args.row.element[0].cells[0].textContent; //keep track of selected user
       var countryUrl = "/Home/CountryByName?countryName=" + args.row.element[0].cells[1].textContent
       $.getJSON(countryUrl,
       function (json, text) {
            $.each(json, function (index, value) {
                   var country = value;
                   var extend = country["Extend"];
                   var zoom = $("#map").igMap("getZoomFromGeographic", extend);
                   $("#map").igMap("option", "windowRect", zoom);
             });
        });
        }
      }
     ,  
   {
        name: 'Sorting',
        type: "remote"
   },
   {
        name: 'Paging',
        type: "local",
        pageSize: 10
   }] 
})

 空間データの動作

アプリケーションを実行し、メニューから「空間データダッシュボード」を選択します。

アプリケーションを実行し、メニュー1から「空間データダッシュボード」を選択します
アプリケーションを実行し、メニュー2から「空間データダッシュボード」を選択します

igGrid から顧客を選択し、クライアントがどの国から来たのかをマップで確認します

igGrid から顧客を選択し、クライアントがどの国から来たのかをマップで確認します
igGrid から顧客を選択し、クライアントが 2 の国をマップでどのように表示しているかを確認します。

サンプルのソースコードは、こちらからダウンロードできます。

このサンプルを実行するには、NorthwindSpatialDemoのサンプル データベースをダウンロードします

いつものように、Twitter: @mihailmateev@Infragisticsでフォローし、ハッシュタグ付きのすべてのツイートをハッシュタグ #infragistcs 付けてフォローし、FacebookGoogle +LinkedInInfragistics Friends User Groupで連絡を取り合うことができます。

デモを予約