使用Xamarin表单放置在何处以及如何从手动创建的DB文件中读取? [英] Where to put and how to read from manually created DB file using Xamarin forms?

查看:89
本文介绍了使用Xamarin表单放置在何处以及如何从手动创建的DB文件中读取?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用数据库浏览器创建了questions.db文件.

I created questions.db file using DB Browser.

这里是:我可爱的.db文件

我想将其添加到Xamarin.Forms解决方案并从中读取数据. (这将是测验应用程序)

I want to add it to Xamarin.Forms solution and read data from it. (This is going to be quiz app)

这听起来很简单,对,但是我被困了几个小时.大多数答案仅链接到此 https://docs.microsoft.com/en-us/xamarin/xamarin-forms/data-cloud/data/databases

That sounds pretty simple, right, but I'm stuck googling for hours. Most answers just link to this https://docs.microsoft.com/en-us/xamarin/xamarin-forms/data-cloud/data/databases

关于手动创建的数据库文件,放置位置等内容,一无所知.

Which explains nothing about the manually created database file, where to put it etc.

这是我要实现的目标:

this is what I'm trying to achieve: https://arteksoftware.com/deploying-a-database-file-with-a-xamarin-forms-app/

可悲的是,该指南已经过时,并且其中的许多内容都无法正常工作.

Sadly, the guide is outdated and many things of it doesn't work.

那么我该把.db文件放在哪里?在MyApp.Android的MyApp.iOS资产和资源中?如果是这样,我该如何获取DBpath字符串以进行新连接?

So where do I put my .db file? In MyApp.Android Assets and Resources for MyApp.iOS? If so, how do I get DBpath string then for new connection?

_database = new SQLiteAsyncConnection(dbPath);

推荐答案

如果您要执行的操作是:

将现有数据库添加到您的项目中,并加载该数据库以供您的应用使用,然后继续阅读.

您需要将数据库文件添加到paltform项目中的特定文件夹(在 Android 中为资产,在 iOS 中只需创建一个文件夹并将文件放在此处),然后使用 DependencyService 进行访问.将数据库文件复制到设备中的某个位置(每个平台上都允许使用App数据文件夹或InternalStorage或watever),然后在 SQLite 构造函数中使用该最终路径.从现在开始,您可以简单地使用该 SQLite 连接来对数据库执行 CRUD 操作.

You need to add your database file to a specific folder in the paltform project (Assets in Android, in iOS you can simply create a folder and put the file there) and use DependencyService to access it. Copy the database file to somewhere in your device (App data folder or InternalStorage or watever is allowed on each platform) and use that final path in the SQLite constructor. From now on, you can simply use that SQLite connection as any other to perform CRUD operation on your Database.

我现在将逐步描述如何实现此目的,从创建一个新的 Xamarin.Forms 项目到从预加载的数据库中读取数据.

I will now describe how to achieve this step by step from creating a new Xamarin.Forms project to reading data from the preloaded database.

注意:以下解决方案将仅涵盖CrossPlatform解决方案的 Android 部分.将此扩展到iOS应该没问题.

Note: the follwoing solution will only cover the Android part of the CrossPlatform solution. Extending this to iOS should be no problem.

免责声明:接下来介绍的代码仅应作为准则,绝不建议我证明它是经过证明的或类似的产品.

创建一个新的 Xamarin.Forms 项目(就我而言,我使用 Visual Studio v.16.3.8 >,并且新项目已安装 Xamarin.Forms 4.2 )

Create a new Xamarin.Forms project (on my case i use Visual Studio v. 16.3.8 and the new project has Xamarin.Forms 4.2 installed)

然后,首先,在所有项目中安装sqlite nuget软件包:

Then, first of all, install sqlite nuget package in ALL your projects:

在App.xaml.cs文件中

In App.xaml.cs file

// Create db static property to perform the 
// Database calls from around the project
public static Database db { get; set; }

public App()
{
    InitializeComponent();


    MainPage = new MainPage();
}

创建一个新的类文件,并将其命名为Database.cs.在那里打开数据库连接.

Create a new class file and name it Database.cs. There you open the database connection.

public class Database
{
    // Create a SQLiteAsyncConnection property to be accessed 
    // publicly thru your App.
    public SQLiteAsyncConnection DBInstance { get; set; }

    public Database(String databasePath)
    {
        DBInstance = new SQLiteAsyncConnection(databasePath);

    }


    private async Task<string> GetDatabaseFilePath()
    {
        return await DependencyService.Get<IPathFinder>().GetDBPath();
    }
}

到目前为止,还不错,但是...预加载数据库的实际路径应该是什么? 好吧,这是下一部分.

So far so good, but... What should actually be the path of your preloaded database? Well, that is the next part.

因此,最大的问题是项目中将先前存在的数据库存储在哪里.

So the big question is where to store your pre-existent database in the project.

一种选择是将其添加为资产.要实现此方法,请执行以下操作:

One option is to add it as an Asset. To implement this approach, do the following:

2.1将数据库文件添加到Android项目中的Assets文件夹中

现在,我们要访问该数据库.为此,请按照以下步骤操作:

Now we want to access that database. To do so, follow the next steps:

2.2在您的App项目中创建一个接口IPathFinder

在那里定义了一个成员GetDBPath()

And there define a single member GetDBPath()

public interface IPathFinder
{

    Task<String> GetDBPath();

}

现在,在您的Android项目中创建一个类文件 PathFinder.cs 来实现此接口

Now, in your Android project create a class file PathFinder.cs to implement this interface

并实现该方法(请注意名称空间上方的Dependency Attribute!)

and implement the method (Note the Dependency Attribute above the namespace!)

using System;
using SysIO = System.IO;
using System.Threading.Tasks;

using Java.IO;

using Xamarin.Forms;

using TestDB.Droid;

[assembly: Dependency(typeof(PathFinder))]
namespace TestDB.Droid
{
    public class PathFinder : IPathFinder
    {
        public async Task<string> GetDBPath()
        {

            String dbPath = String.Empty;

            if (await PermissonManager.GetPermission(PermissonManager.PermissionsIdentifier.Storage))
            {

                String systemPath = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.RootDirectory.Path).Path;

                String tempFolderPath = SysIO::Path.Combine(systemPath, "MytestDBFolder");
                if (!SysIO::File.Exists(tempFolderPath))
                {
                    new File(tempFolderPath).Mkdirs();
                }

                dbPath = SysIO::Path.Combine(tempFolderPath, "test.db");

                if (!SysIO::File.Exists(dbPath))
                {
                    Byte[] dbArray;
                    using (var memoryStream = new SysIO::MemoryStream())
                    {
                        var dbAsset = MainActivity.assets.Open("test.db");
                        dbAsset.CopyTo(memoryStream);
                        dbArray = memoryStream.ToArray();
                    }    

                    SysIO.File.WriteAllBytes(dbPath, dbArray);

                }    

            }    

            return dbPath;
        }
    }
}

在GetDBPath()方法中,首先要注意的是GetPermission方法.从Android API 23开始,这是必需的,以便管理应用程序权限.

In the GetDBPath() method, the first to note is the GetPermission method. This is needed since Android API 23 in order to manage the App permissions.

在您的Android项目中创建一个名为PermissonManager的文件

Create a file called PermissonManager in your Android project

并在下面添加代码

using System;
using System.Threading.Tasks;
using Android;
using Android.App;
using Android.Content.PM;
using Android.OS;
using Android.Support.V4.App;

namespace TestDB.Droid
{
    public class PermissonManager
    {

        public enum PermissionsIdentifier
        {
            Storage // Here you can add more identifiers.
        }

        private static String[] GetPermissionsRequired(PermissionsIdentifier identifier)
        {

            String[] permissions = null;


            if (identifier == PermissionsIdentifier.Storage)

                permissions = PermissionExternalStorage;


            return permissions;

        }

        private static Int32 GetRequestId(PermissionsIdentifier identifier)
        {

            Int32 requestId = -1;


            if (identifier == PermissionsIdentifier.Storage)

                requestId = ExternalStorageRequestId;


            return requestId;

        }


        public static TaskCompletionSource<Boolean> PermissionTCS;


        public static readonly String[] PermissionExternalStorage = new String[] { Manifest.Permission.ReadExternalStorage, Manifest.Permission.WriteExternalStorage };

        public const Int32 ExternalStorageRequestId = 2;



        public static async Task<Boolean> GetPermission(PermissionsIdentifier identifier)
        {

            Boolean isPermitted = false;

            if ((Int32)Build.VERSION.SdkInt < 23)

                isPermitted = true;

            else

                isPermitted = await GetPermissionOnSdk23OrAbove(GetPermissionsRequired(identifier), GetRequestId(identifier));


            return isPermitted;

        }



        private static Task<Boolean> GetPermissionOnSdk23OrAbove(String[] permissions, Int32 requestId)
        {

            PermissionTCS = new TaskCompletionSource<Boolean>();

            if (MainApplication.CurrentContext.CheckSelfPermission(permissions[0]) == (Int32)Permission.Granted)

                PermissionTCS.SetResult(true);

            else

                ActivityCompat.RequestPermissions((Activity)MainApplication.CurrentContext, permissions, requestId);


            return PermissionTCS.Task;

        }


        public static void OnRequestPermissionsResult(Permission[] grantResults)
        {

            PermissionTCS.SetResult(grantResults[0] == Permission.Granted);

        }

    }
}

在该类中,您会注意到MainApplication的存在,它提供了CurrentContext.您还必须添加该类文件

In that class you note the presence of MainApplication, which provides the CurrentContext. You will also have to add that class file

并在其中添加以下代码

using System;

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;


namespace DemoDB.Droid
{
    [Application]
    public partial class MainApplication : Application, Application.IActivityLifecycleCallbacks
    {

        private static Context _currentContext = Application.Context;
        internal static Context CurrentContext
        {
            get => _currentContext;
            private set
            {
                _currentContext = value;
            }
        }


        internal static String FileProviderAuthority
        {
            get => MainApplication.CurrentContext.ApplicationContext.PackageName + ".fileprovider";
        }


        public MainApplication(IntPtr handle, JniHandleOwnership transfer) : base(handle, transfer)
        {

        }


        public override void OnCreate()
        {

            base.OnCreate();

            RegisterActivityLifecycleCallbacks(this);

        }


        public override void OnTerminate()
        {

            base.OnTerminate();

            UnregisterActivityLifecycleCallbacks(this);

        }


        public void OnActivityCreated(Activity activity, Bundle savedInstanceState)
        {

            CurrentContext = activity;

        }


        public void OnActivityDestroyed(Activity activity)
        {

        }


        public void OnActivityPaused(Activity activity)
        {

        }


        public void OnActivityResumed(Activity activity)
        {

            CurrentContext = activity;

        }


        public void OnActivitySaveInstanceState(Activity activity, Bundle outState)
        {

        }


        public void OnActivityStarted(Activity activity)
        {

            CurrentContext = activity;

        }


        public void OnActivityStopped(Activity activity)
        {

        }    
    }
}

然后,您的 PermissonManager 即将准备就绪.现在,您只需要覆盖 MainActivity 文件

Then your PermissonManager is almost ready. Now you just have to override OnRequestPermissionsResult in the MainActivity file

public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
    PermissonManager.OnRequestPermissionsResult(grantResults);
    base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}

回到GetPath()方法,您会看到一个神秘的MainActivity.assets属性调用.必须在MainActivity中如下创建

Getting back to the GetPath() method, you see a mysterious MainActivity.assets property call. This has to be created in the MainActivity as follows

public static AssetManager assets;

protected override void OnCreate(Bundle savedInstanceState)
{
    TabLayoutResource = Resource.Layout.Tabbar;
    ToolbarResource = Resource.Layout.Toolbar;

    assets = this.Assets;

    base.OnCreate(savedInstanceState);

    Xamarin.Essentials.Platform.Init(this, savedInstanceState);
    global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
    LoadApplication(new App());
}

快要准备好了!现在,您只需调用数据库即可.

Almost ready! Now you just call your database.

在主页的OnAppearing上,对数据库进行简单的调用,以创建并访问它.

From the OnAppearing of the Main page, make a simple call to the database, to create it and access it.

protected override async void OnAppearing()
{
    String databasePath = await Database.GetDatabaseFilePath();

    App.db = new Database(databasePath);

    var table = await App.db.DBInstance.CreateTableAsync<Category>();

    // here Category is a class that models the objects 
    // present in my pre-existent database
    List<Category> categories = new List<Category>();

    categories = await App.db.DBInstance.Table<Category>().ToListAsync();

    base.OnAppearing();
}

就是这样.

我希望这会有所帮助:P

I hope this is helpful :P

这篇关于使用Xamarin表单放置在何处以及如何从手动创建的DB文件中读取?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆