【问题标题】:Custom SQLite functions in Xamarin.iOSXamarin.iOS 中的自定义 SQLite 函数
【发布时间】:2016-12-31 15:39:23
【问题描述】:

我正在开发 Xamarin.iOS 上的 Sqlite 自定义功能。我从这里得到了答案:Show markers on map within a given radius (Xamarin.Android) 但我遇到了

的问题

正在尝试 JIT 编译方法 '(包装器本机到托管) Mono.Data.Sqlite.SqliteFunction:ScalarCallback (intptr,int,intptr)' 使用 --aot-only 运行时。

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

我不确定如何使用MonoPInvokeCallbackAttribute 注释方法并使其成为静态,因为 SqliteFunction 类中的方法已被覆盖,因此无法使其成为静态。 如果有人可以帮助我理解该解决方案或提供该解决方案缺少的步骤,那就太好了。

【问题讨论】:

    标签: ios sqlite xamarin xamarin.ios mono


    【解决方案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);
        }
    }
    

    【讨论】:

    • 1.我需要添加包“SQLitePCLRaw.ugly”吗?因为 SQLitePCL.raw 是它的更新版本。 2. "ugly.open" 这里的丑是什么? 3. UDF 代码将在 iOS 部分,或者我可以在 PCL 中编写
    • @Iducool 1) 我目前正在使用 v1.1.1 of SQLitePCLRaw.???? (ugly, core, raw, green, sqlite3.ios_unified, ...) 2) ugly 来自@987654335 @,C 风格的 C# API,提供最低级别的 SQLite C# 访问,非常原始,因此命名为 ugly... 3) 虽然这种情况下的 SQLite UDF 只是跨平台 C#, MonoPInvokeCallbackAttribute 不是,仅在 Xamarin.iOS 中可用,因此 Xamarin.iOS 应用程序或库或前者之一的共享项目引用。我通常使用共享项目和#if __IOS__ 属性打开/关闭静态 UDF 方法
    • 获取异常:无法从程序集“SQLitePCLRaw.provider.sqlite3”加载类型“SQLitePCL.SQLite3Provider_sqlite3”,
    • @Iducool 不确定你是如何设置的,但使用 SQLitePCL.Batteries.Init(); 而不是 SQLitePCL.raw.SetProvider(new SQLitePCL.SQLite3Provider_sqlite3());
    • 当我们添加 sqlite-net-pcl 时,它会占用一些旧的 row 和 core 包。刚刚更新,一切都像魅力一样工作。
    猜你喜欢
    • 2012-10-30
    • 2011-09-11
    • 2011-01-07
    • 2011-05-13
    • 2016-03-25
    • 2019-08-16
    • 1970-01-01
    • 2011-06-07
    • 1970-01-01
    相关资源
    最近更新 更多