简体   繁体   English

iOS 应用程序中的 SQLite 问题与 Xamarin forms

[英]Problem with SQLite in iOS App with Xamarin forms

I have created my app in Visual Studio 2019 for Android and iOS.我在 Visual Studio 2019 中为 Android 和 iOS 创建了我的应用程序。

If I DEBUG my iOS app it is working perfectly as it should.如果我调试我的 iOS 应用程序,它应该可以正常工作。 It is debugged with iPhoneSimulator.它是用 iPhoneSimulator 调试的。

But if I rollout my RELEASE and test in on for example iPad, it seems that it can not find the SQLite DB whitch is stored like this:但是,如果我推出我的 RELEASE 并在例如 iPad 上进行测试,它似乎找不到 SQLite DB whitch 存储如下:

string dbpath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "MyDatabase.db");

Is there a problem maybe with the SpecialFolder 'Personal' on iOS? iOS 上的 SpecialFolder 'Personal' 是否有问题?

This code will be processes during start up:此代码将是启动期间的进程:

    if (!File.Exists(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "MyDatabase.db")))
    {
        DataHelper.Database db = new DataHelper.Database();
        if (!db.CreateDatabase())
        {
            DisplayAlert("Error", "DB could not be loaded !", "OK");
        }
    }

this is my DatabaseHelper class:这是我的数据库助手 class:

    namespace VoTa.DataHelper
    {
        public class Database
        {
                    readonly string dbpath = Data.GetPath();
        private static readonly string ftpurl = "myURL";
    
            public bool CreateDatabase()
            {
                try
                {
                    var connection = new SQLiteConnection(dbpath);            
                        connection.CreateTable<Belohnungen>();
                        connection.CreateTable<Vokabeln>();
                        connection.CreateTable<EigeneVokabel>();
                        connection.Close();
                        return true;               
                }
                catch (SQLiteException)
                {
                    //Log.Info("SQLite Fehler!", ex.Message);
                    return false;
                }
            }

   public void InsertIntoVokabeln(string dateiname)
        {
            

            String voakbelURL = ftpurl + dateiname;
            string id;
            string fremdsprache;
            string deutsch;
            string info1;
            string info2;

            var connection = new SQLiteConnection(dbpath);

            connection.Query<Vokabeln>("Delete from Vokabeln");

            XmlDocument xmldoc = new XmlDocument();
            xmldoc.Load(voakbelURL);
            var vList = xmldoc.SelectNodes("/Vokabel/VokabelModel");

            try
            {
                foreach (XmlNode node in vList)
                {
                    id = node["Id"].InnerText;
                    fremdsprache = node["fremdsprache"].InnerText;
                    deutsch = node["deutsch"].InnerText;
                    info1 = "";
                    info2 = "";

                    if (node["info1"] != null)
                    {
                        info1 = node["info1"].InnerText;
                    }

                    if (node["info2"] != null)
                    {
                        info1 = node["info2"].InnerText;
                    }

                    Vokabeln vokabel = new Vokabeln
                    {
                        Fremdsprache = fremdsprache,
                        Deutsch = deutsch,
                        Info1 = info1,
                        Info2 = info2
                    };

                    connection.Insert(vokabel);
                }
            }
            catch (Exception)
            {
                return;
            }
            finally
            {
                connection.Close();
            }
        }

        public void InsertIntoBelohnungen(string dateiname)
        {
            String belohunngURL = ftpurl + dateiname;
            string id;
            string beloh;
            string info1;
            string info2;

            var connection = new SQLiteConnection(dbpath);
            connection.Query<Belohnungen>("Delete from Belohnungen");

            XmlDocument xmldoc = new XmlDocument();
            xmldoc.Load(belohunngURL);
            var vList = xmldoc.SelectNodes("/Belohnung/BelohnungModel");

            try
            {
                foreach (XmlNode node in vList)
                {
                    id = node["Id"].InnerText;
                    beloh = node["Belohnung"].InnerText;
                    info1 = "";
                    info2 = "";

                    if (node["info1"] != null)
                    {
                        info1 = node["info1"].InnerText;
                    }

                    if (node["info2"] != null)
                    {
                        info1 = node["info2"].InnerText;
                    }

                    Belohnungen belohnung = new Belohnungen
                    {
                        Belohnung = beloh,
                        Info1 = info1,
                        Info2 = info2
                    };

                    connection.Insert(belohnung);
                }
            }
            catch (Exception)
            {
                return;
            }
            finally
            {
                connection.Close();
            }
        }

It is working on iPhoneSimulator but not in "real".它正在 iPhoneSimulator 上工作,但不是“真实的”。

Add DB file in the AppDelegate.cs file like:在 AppDelegate.cs 文件中添加 DB 文件,如:

string sqliteFilename = "MyDatabase.db";
            string folderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal),"..","Library");
            string dbpath = Path.Combine(folderPath, sqliteFilename);
            LoadApplication(new App(dbpath));

My App.xaml.cs:我的 App.xaml.cs:

   public App(string dbpath)
    {
        InitializeComponent();

        Data.SetPath(dbpath);
        MainPage = new NavigationPage(new MainPage());         
    }

My MainView:我的主视图:

switch (Device.RuntimePlatform)
            {
                case Device.iOS:
                    if (!File.Exists(Data.GetPath()))
                    {
                        DataHelper.Database db = new DataHelper.Database();
                        if (!db.CreateDatabase())
                        {
                            DisplayAlert("Fehler", "Datenbank konnte nicht erstellt werden !", "OK");
                        }
                    }
                    break;
                case Device.Android:
                    if (!File.Exists(Data.GetPath()))
                    {
                        DataHelper.Database db = new DataHelper.Database();
                        if (!db.CreateDatabase())
                        {
                            DisplayAlert("Fehler", "Datenbank konnte nicht erstellt werden !", "OK");
                        }
                    }
                    break;
            }

This does not gave me exception.这并没有给我例外。

I get this exception:我得到这个例外:

   private void Starten()
    {
        DataHelper.Database db = new DataHelper.Database();

        try
        {
            List<Vokabeln> myvokabel = db.SelectTableVokabeln(anzahlVokabel).ToList();

            frage.Clear();
            antwort.Clear();
            info1.Clear();
            info2.Clear();
            belohnung.Clear();

            int test = myvokabel.Count();

            foreach (var item in myvokabel)
            {
                if (richtung == 1)
                {
                    frage.Add(item.Deutsch);
                    antwort.Add(item.Fremdsprache);
                }
                else
                {
                    frage.Add(item.Fremdsprache);
                    antwort.Add(item.Deutsch);
                    info1.Add(item.Info1);
                    info2.Add(item.Info2);
                }
            }

            List<Belohnungen> mybelohnung = db.SelectTableBelohnungen().ToList();

            foreach (var bel in mybelohnung)
            {
                belohnung.Add(bel.Belohnung);
            }

            //DisplayAlert("Info", "Vokabeln und Belohnungen wurden geladen!", "OK");
        }
        catch (Exception)
        {
            //Log.Info("interner Fehler!", ex.Message);
            DisplayAlert("Fehler", "Es ist ein Fehler aufgetreten", "OK");
        }
    }

Database.cs数据库.cs

 public List<Vokabeln> SelectTableVokabeln(int anzahl)
        {
            try
            {
                var connection = new SQLiteConnection(dbpath);
                var abfrage = connection.Query<Vokabeln>(string.Format("SELECT ID, Fremdsprache, Deutsch, Info1, Info2 FROM Vokabeln ORDER BY RANDOM() LIMIT {0}", anzahl));
                //return connection.Table<Vokabeln>().ToList();
                return abfrage;
            }
            catch (SQLiteException)
            {
                //Log.Info("SQLite Fehler!", ex.Message);
                return null;
            }
        }

        public List<Belohnungen> SelectTableBelohnungen()
        {
            try
            {
                var connection = new SQLiteConnection(dbpath);

                return connection.Table<Belohnungen>().ToList();                
            }
            catch (SQLiteException)
            {
                //Log.Info("SQLite Fehler!", ex.Message);
                return null;
            }
        }

Any help?有什么帮助吗?

Thank you.谢谢你。

I remember having had similar issues when trying to handle the file in shared code.我记得在尝试处理共享代码中的文件时遇到过类似的问题。

Strangely enough, creating an interface in my shared code with a native implementation on both iOS and Android resolved the issue.奇怪的是,在我的共享代码中使用 iOS 和 Android 上的本机实现创建一个接口解决了这个问题。

Here is my code to retrieve the connection from within my iOS project in a native implementation of an interface from the shared project called IFileService:这是我的代码,用于在名为 IFileService 的共享项目的接口的本机实现中从我的 iOS 项目中检索连接:

    public SQLite.SQLiteConnection GetDbConnection()
    {
        try
        {
            string sqliteFilename = "MyAppDb.db3";
            string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal) + sqliteFilename);
            SQLiteConnection conn = new SQLite.SQLiteConnection(path, SQLiteOpenFlags.Create | SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.NoMutex);

            return conn;
        }
        catch (Exception ex)
        {
            Logger.Fatal(ex, "An exception occurred at GetConnection");
            Logger.Trace("Stack Trace: {0}", ex.StackTrace);
        }

        return null;
    }

Also I would suggest that you don't access your connection the way you are doing it right now, as另外,我建议您不要以现在的方式访问连接,因为

var connection = new SQLiteConnection(dbpath); var connection = new SQLiteConnection(dbpath);

will keep your connection open, which will most probably cause problems, if you want to use another connection.将使您的连接保持打开状态,如果您想使用另一个连接,这很可能会导致问题。 In order to ensure that your connection is properly closed, I would highly recommend to manage it in a using block:为了确保您的连接正确关闭,我强烈建议在 using 块中管理它:

using(SQLiteConnection connection = iFileService.GetDbConnection())
{
    connection.CreateTable<Belohnungen>();
    connection.CreateTable<Vokabeln>();
    connection.CreateTable<EigeneVokabel>();
}           

This way the connection will be properly closed and disposed when your database access is finished.这样,当您的数据库访问完成时,连接将被正确关闭和处理。 Also ensure that you always access your database connections that way whenever you get or store data in SQLite.还要确保在 SQLite 中获取或存储数据时始终以这种方式访问数据库连接。

PS: if you are using a newer version of sqlite, you might need to construct your database with PS:如果您使用的是较新版本的 sqlite,您可能需要使用

SQLiteConnection connection = new SQLiteConnection(dbpath);

instead of the way I am creating it.而不是我创建它的方式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM