2016-12-31 60 views
1

我正在使用Xamarin.iOS上的Sqlite自定义函数。我得到的答案从这里:Show markers on map within a given radius (Xamarin.Android)但我遇到的Xamarin.iOS中的自定义SQLite函数

问题试图JIT编译方法“(包装机设备到管理) Mono.Data.Sqlite.SqliteFunction:ScalarCallback(IntPtr的,INT,IntPtr的)' ,同时运行 - 只 - 。

在栈上搜索后,我发现这里是一个解决方案:custom functions SQLite with Mono但解决方案提到有很难让我理解。

我不确定如何使用MonoPInvokeCallbackAttribute注释方法并将其设置为静态,因为SqliteFunction类中的方法会被覆盖,因此无法将其设置为静态。 如果有人能够帮助我理解该解决方案或提供该解决方案中缺少的步骤,那将会很棒。

回答

1

我使用流行的sqlite-net(由Frank A. Krueger提供),它又使用SQLitePCLRaw.bundle_greenSQLitePCL.raw(均由Eric Sink提供)。

因此,您可以使用基于SQLitePCLRaw.ugly的API轻松设置和访问SQLite UDF。

Xamarin.iOSSQLite用户定义函数(UDF):

delegate void SQLiteCallback(sqlite3_context ctx, object user_data, sqlite3_value[] args); 
[MonoPInvokeCallback(typeof(SQLiteCallback))] 
static void UDFDistanceFunction(sqlite3_context ctx, object user_data, sqlite3_value[] args) 
{ 
    double radius = 6367; 
    var lat1 = raw.sqlite3_value_double(args[0]); 
    var lng1 = raw.sqlite3_value_double(args[1]); 
    var lat2 = raw.sqlite3_value_double(args[2]); 
    var lng2 = raw.sqlite3_value_double(args[3]); 
    var result = radius * 2 * Math.Asin(Math.Min(1, Math.Sqrt((Math.Pow(Math.Sin((lat2 * (Math.PI/180) - lat1 * (Math.PI/180))/2.0), 2.0) + Math.Cos(lat1 * (Math.PI/180)) * Math.Cos(lat2 * (Math.PI/180)) * Math.Pow(Math.Sin((lng2 * (Math.PI/180) - lng1 * (Math.PI/180))/2.0), 2.0))))); 
    raw.sqlite3_result_double(ctx, result); 
} 

用法:

使用sqlite-net-pcl设置表,加载/更新数据,.....

SQLitePCL.raw.SetProvider(new SQLitePCL.SQLite3Provider_sqlite3()); 
var dbName = Path.Combine(Path.GetTempPath(), "StackOverflow.db"); 
var db = new SQLiteConnection(dbName, SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.Create, true); 
db.CreateTable<BarLocations>(); 
db.Insert(new BarLocations() 
{ 
    name = "FOOBAR", lat = 47.60357, lng = -122.3295 
}); 

使用SQLitePCLRaw.ugly用SQLite创建和查询UDF

SQLitePCL.raw.SetProvider(new SQLitePCL.SQLite3Provider_sqlite3()); 
var dbName = Path.Combine(Path.GetTempPath(), "StackOverflow.db"); 
using (sqlite3 dbRaw = ugly.open(dbName)) 
{ 
    dbRaw.create_function("distance", 4, null, UDFDistanceFunction); 
    double currentLatitude = 47.0; 
    double currentLongitude = -122.0; 
    var sql = $"SELECT * FROM barlocations WHERE distance('{currentLatitude.ToString()}', '{currentLongitude.ToString()}', barlocations.lat, barlocations.lng) <= 100 ;"; 
    var locs = dbRaw.query<BarLocations>(sql); 
    foreach (var loc in locs) 
    { 
     Console.WriteLine(loc.name); 
    } 
} 
+0

1.我需要添加包“SQLitePCLRaw.ugly”吗?因为SQLitePCL.raw是它的更新版本。 2.“ugly.open”这里的丑陋是什么? 3. UDF代码将在IOS部分或我可以在PCL – Iducool

+0

@Iducool 1写)我目前使用SQLitePCLRaw的'V1.1.1。????'(难看,核心,生,绿色,sqlite3.ios_unified ,...)2)'ugly'来自'SQLitePCLRaw.ugly',一个'C'风格的C#API,它提供了最低级别的SQLite C#访问,非常原始,因此被命名为*丑陋* ... 3)虽然SQLite在这种情况下,UDF只是跨平台的C#,而“MonoPInvokeCallbackAttribute”不是,只能在'Xamarin.iOS'中使用,所以'Xamarin.iOS'应用程序或库或共享项目由前者之一引用。我通常使用一个共享的项目和'#如果__IOS__'开/关静态UDF方法 – SushiHangover

+0

获取异常属性:未能从程序集加载类型“SQLitePCL.SQLite3Provider_sqlite3“SQLitePCLRaw.provider.sqlite3, – Iducool