C#からSpatiaLiteを利用する
SpatiaLiteとはSQLite上でGISを扱えるようにする拡張モジュールです。
PostgreSQLに対するPostGISのような位置づけです。
さて、こいつをC#で動かそうとすると、なかなか大変だったので、忘れないように手順をメモしておきます。
前提
今回は、
- Visual Studio (VS)でC#のプロジェクトを作る。
- そのプロジェクトのSystem.Data.SQLite上でSpatiaLiteの拡張モジュールをロードし使う
- x64向けビルドを作る
という前提で話を進めます。
System.Data.SQLiteの準備
まずは、VSでSQLiteが使えるように、C#のプロジェクトのNuGetでSystem.Data.SQLiteをインストールします。
また、構成マネージャを使ってx64ビルドを作れるようにしておきます。
SpatiaLiteのダウンロード
SpatiaLite本家サイト:http://www.gaia-gis.it/gaia-sins/
こちらのページの最下部にMS Windows binariesというコーナーがあるので、そこのcurrent stable versionのamd64を選択します。
ファイル一覧ページに遷移したら、mod_spatialite-4.3.0a-win-amd64.7zを選択してダウンロード。
で、この7zファイルを解凍すると、mod_spatialite.dll以下、依存するdll群がまとめて入っているわけですが、こいつが曲者。
このモジュールたちをそのまま使おうとすると、mod_spatialite.dllのロード時にlibstdc++_64-6.dllでアクセスバイオレーションが発生して落ちます。
そこで、アクセスバイオレーションの発生しないものに置き換える必要があります。
libstdc++_64-6.dllの置き換え
libstdc++_64-6.dllは、MinGW64に同梱されています。
MinGW64: https://sourceforge.net/projects/mingw-w64/?source=typ_redirect
上記サイトからダウンロードし、インストールします。こんな感じの設定でインストールしました。
インストールが完了したら、インストール先ディレクトリのbin以下の「libstdc++-6.dll」「libgcc_s_seh-1.dll」の2つのファイルをコピーし、前節のspatialiteのdll群のものと入れ替えます。
置き換える際、ファイル名は以下のようにしてください。
- 「libstdc++-6.dll」はmod_spatialiteに同梱されているほうに合わせて「libstdc++_64-6.dll」にリネームする。
- 「libgcc_s_seh-1.dll」は「libgcc_s_seh-1.dll」のままにする。
「libgcc_s_seh-1.dll」のほうもmod_spatialite同梱版に合わせた名前にリネームすると、私の環境では正しく動作しませんでした。
まぎらわしいので、もともと同梱されていた「libgcc_s_seh_64-1.dll」は削除してしまいましょう。
dll入れ替え後のディレクトリはこんな感じになります。
図中、選択されている2ファイルが入れ替えたものです。
なお、このdll入れ替えについては以下を参考にしました。
http://blog.jrg.com.br/2016/04/25/Fixing-spatialite-loading-problem/
ビルドイベントの設定
mod_spatialite.dll以下関連dll群を、VSのC#プロジェクトが出力するexeと同じディレクトリにコピーするようビルドイベントを設定します。
プロジェクトのプロパティの「ビルドイベント」から、「ビルド後イベントのコマンドライン」に以下のような感じで書いておきましょう。
copy <mod_spatialiteのあるディレクトリ>\*.dll $(ProjectDir)$(OutDir)
動作確認
さて、ではいよいよ動作確認です。以下のようなコードを実行してみましょう。
using System;
using System.Collections.Generic;
using System.Data.SQLite;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace cstx64
{
class Program
{
private static void ExecuteNonQuery(string sql, SQLiteConnection conn)
{
using (var command = new SQLiteCommand(sql, conn))
{
command.ExecuteNonQuery();
}
}
private static void ExecuteScalar(string sql, SQLiteConnection conn)
{
using (var command = new SQLiteCommand(sql, conn))
{
command.ExecuteScalar();
}
}
private static void LoadExtension(SQLiteConnection conn)
{
var modulePath = @"mod_spatialite";
conn.EnableExtensions(true);
conn.LoadExtension(modulePath);
}
public static void Main(string[] args)
{
string fileName = @".\test.db";
if (System.IO.File.Exists(fileName))
{
System.IO.File.Delete(fileName);
}
using (var conn = new SQLiteConnection(string.Format("Data Source={0};Version=3", fileName)))
{
conn.Open();
LoadExtension(conn);
string sql = " CREATE TABLE IF NOT EXISTS t (id, name, point)";
ExecuteNonQuery(sql, conn);
sql = "INSERT INTO t VALUES(1, 'some', ST_GeomFromText('POINTZ(1.0 2.0 3.0)'))";
ExecuteNonQuery(sql, conn);
sql = "SELECT id, name, ST_AsText(point) AS pt FROM t";
using (var command = new SQLiteCommand(sql, conn))
{
using (var dr = command.ExecuteReader())
{
while (dr.Read())
{
int id = Convert.ToInt32(dr["id"].ToString());
string name = dr["name"].ToString();
string pt = dr["pt"].ToString(); ;
Console.WriteLine(String.Format("{0}, {1}, {2}", id, name, pt));
}
}
}
conn.Close();
}
}
}
}
LoadExtension
メソッドで、SpatiaLiteの拡張モジュールをロードしています。
ロードする前にEnableExtensions
で拡張を有効化しなければならないので注意です。
(さらにいうと、このEnableExtensions
とLoadExtension
の操作は、SQLiteConnection
インスタンスごとに実行する必要があります。)
ロードが正しく行われると、その後のINSERT文、SELECT文にあるようなST_xxx
の関数が利用できるようになります。
ここでは適当に座標が(1,2,3)の点をpointカラムに投入し、それが取れていることを確認しています。
1, some, POINT Z(1 2 3)
これで動作確認完了です。お疲れさまでした。
Author And Source
この問題について(C#からSpatiaLiteを利用する), 我々は、より多くの情報をここで見つけました https://qiita.com/baikichiz/items/98fa9f433cb0a94cf04f著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .