将数据存储在本地 SQLite.NET 数据库中

在本快速入门中,你将了解如何:

  • 在本地将数据存储在 SQLite.NET 数据库中。

本快速入门演练如何通过 Xamarin.Forms Shell 应用程序将数据存储在本地 SQLite.NET 数据库中。 最终的应用程序如下所示:

Notes 页面便签输入页面

先决条件

在尝试本快速入门之前,应成功完成上一个快速入门

使用 Visual Studio 更新应用

  1. 启动 Visual Studio 并打开 Notes 解决方案。

  2. 在“解决方案资源管理器”中,右键单击“Notes”解决方案,选择“管理解决方案 NuGet 包...”:

    管理 NuGet 包

  3. 在“NuGet 包管理器”中,选择“浏览”选项卡,再搜索“sqlite-net-pcl”NuGet 包 。

    警告

    许多 NuGet 包都有着类似的名称。 正确的包具有以下属性:

    尽管包的名称如此,此 NuGet 包也可以用于 .NET Standard 项目。

    在“NuGet 包管理器”中,选择正确的“sqlite-net-pcl”包,选中“项目”复选框,然后单击“安装”按钮将其添加到解决方案中 :

    选择 sqlite-net-pcl

    此包将用于将数据库操作合并到应用程序中,并将添加到解决方案中的每个项目中。

    重要

    SQLite.NET 是 praeclarum/sqlite-net 存储库支持的第三方库。

    关闭“NuGet 包管理器”。

  4. 在“解决方案资源管理器”的“Notes”项目中,打开“Models”文件夹中的“Note.cs”,并将现有代码替换为以下代码:

    using System;
    using SQLite;
    
    namespace Notes.Models
    {
        public class Note
        {
            [PrimaryKey, AutoIncrement]
            public int ID { get; set; }
            public string Text { get; set; }
            public DateTime Date { get; set; }
        }
    }
    

    此类定义一个 Note 模型,该模型将在应用程序中存储有关每个便笺的数据。 使用 PrimaryKeyAutoIncrement 特性标记 ID 属性,以确保 SQLite.NET 数据库中的每个 Note 实例均具有 SQLite.NET 提供的唯一 ID。

    通过按 Ctrl+S,保存对 Note.cs 所做的更改。

    警告

    由于在后续步骤中将修复一些错误,暂时不会生成应用程序。

  5. 在“解决方案资源管理器”中,将名为“Data”的新文件夹添加到“Notes”项目。

  6. 在“解决方案资源管理器”的“Notes”项目中,将名为“NoteDatabase”的新类添加到“Data”文件夹。

  7. 在 NoteDatabase.cs 中,将现有代码替换为以下代码:

    using System.Collections.Generic;
    using System.Threading.Tasks;
    using SQLite;
    using Notes.Models;
    
    namespace Notes.Data
    {
        public class NoteDatabase
        {
            readonly SQLiteAsyncConnection database;
    
            public NoteDatabase(string dbPath)
            {
                database = new SQLiteAsyncConnection(dbPath);
                database.CreateTableAsync<Note>().Wait();
            }
    
            public Task<List<Note>> GetNotesAsync()
            {
                //Get all notes.
                return database.Table<Note>().ToListAsync();
            }
    
            public Task<Note> GetNoteAsync(int id)
            {
                // Get a specific note.
                return database.Table<Note>()
                                .Where(i => i.ID == id)
                                .FirstOrDefaultAsync();
            }
    
            public Task<int> SaveNoteAsync(Note note)
            {
                if (note.ID != 0)
                {
                    // Update an existing note.
                    return database.UpdateAsync(note);
                }
                else
                {
                    // Save a new note.
                    return database.InsertAsync(note);
                }
            }
    
            public Task<int> DeleteNoteAsync(Note note)
            {
                // Delete a note.
                return database.DeleteAsync(note);
            }
        }
    }
    

    此类包含用于创建数据库、从中读取数据、向其写入数据以及从中删除数据的代码。 代码使用将数据库操作移动到后台线程的异步 SQLite.NET API。 此外,NoteDatabase 构造函数将数据库文件的路径作为参数。 在下一步中,此路径由 App 类提供。

    通过按 Ctrl+S,保存对 NoteDatabase.cs 所做的更改。

    警告

    由于在后续步骤中将修复一些错误,暂时不会生成应用程序。

  8. 在“解决方案资源管理器”的“Notes”项目中,展开“App.xaml”,然后双击“App.xaml.cs”将其打开 。 然后将现有代码替换为以下代码:

    using System;
    using System.IO;
    using Notes.Data;
    using Xamarin.Forms;
    
    namespace Notes
    {
        public partial class App : Application
        {
            static NoteDatabase database;
    
            // Create the database connection as a singleton.
            public static NoteDatabase Database
            {
                get
                {
                    if (database == null)
                    {
                        database = new NoteDatabase(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Notes.db3"));
                    }
                    return database;
                }
            }
    
            public App()
            {
                InitializeComponent();
                MainPage = new AppShell();
            }
    
            protected override void OnStart()
            {
            }
    
            protected override void OnSleep()
            {
            }
    
            protected override void OnResume()
            {
            }
        }
    }
    

    此代码定义一个 Database 属性,该属性以单一实例的形式创建新 NoteDatabase 实例,将数据库的文件名作为参数传入 NoteDatabase 构造函数。 以单一实例的形式公开数据库的优势是,所创建的单一数据库连接在应用程序运行时保持打开状态,因此避免了每次执行数据库操作时打开和关闭数据库文件所产生的费用。

    通过按 Ctrl+S,保存对 App.xaml.cs 所做的更改。

    警告

    由于在后续步骤中将修复一些错误,暂时不会生成应用程序。

  9. 在“解决方案资源管理器”的“Notes”项目中,展开“Views”文件夹中的“NotesPage.xaml”,并打开“NotesPage.xaml.cs” 。 然后将 OnAppearingOnSelectionChanged 替换为以下代码:

    protected override async void OnAppearing()
    {
        base.OnAppearing();
    
        // Retrieve all the notes from the database, and set them as the
        // data source for the CollectionView.
        collectionView.ItemsSource = await App.Database.GetNotesAsync();
    }
    
    async void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (e.CurrentSelection != null)
        {
            // Navigate to the NoteEntryPage, passing the ID as a query parameter.
            Note note = (Note)e.CurrentSelection.FirstOrDefault();
            await Shell.Current.GoToAsync($"{nameof(NoteEntryPage)}?{nameof(NoteEntryPage.ItemId)}={note.ID.ToString()}");
        }
    }    
    

    OnAppearing 方法使用存储在数据库中的任何便笺填充 CollectionViewOnSelectionChanged 方法导航到 NoteEntryPage,将所选的 Note 对象的 ID 属性作为查询参数传递。

    通过按 Ctrl+S,保存对 NotesPage.xaml.cs 所做的更改。

    警告

    由于在后续步骤中将修复一些错误,暂时不会生成应用程序。

  10. 在“解决方案资源管理器”中,展开“Views”文件夹中的“NoteEntryPage.xaml”,并打开“NoteEntryPage.xaml.cs” 。 然后将 LoadNoteOnSaveButtonClickedOnDeleteButtonClicked 替换为以下代码:

    async void LoadNote(string itemId)
    {
        try
        {
            int id = Convert.ToInt32(itemId);
            // Retrieve the note and set it as the BindingContext of the page.
            Note note = await App.Database.GetNoteAsync(id);
            BindingContext = note;
        }
        catch (Exception)
        {
            Console.WriteLine("Failed to load note.");
        }
    }
    
    async void OnSaveButtonClicked(object sender, EventArgs e)
    {
        var note = (Note)BindingContext;
        note.Date = DateTime.UtcNow;
        if (!string.IsNullOrWhiteSpace(note.Text))
        {
            await App.Database.SaveNoteAsync(note);
        }
    
        // Navigate backwards
        await Shell.Current.GoToAsync("..");
    }
    
    async void OnDeleteButtonClicked(object sender, EventArgs e)
    {
        var note = (Note)BindingContext;
        await App.Database.DeleteNoteAsync(note);
    
        // Navigate backwards
        await Shell.Current.GoToAsync("..");
    }
    

    NoteEntryPage使用 LoadNote 方法从数据库中检索注释(其 ID 已作为查询参数传递到页面),并将其存储为页面的 BindingContext 中的 Note 对象。 执行 OnSaveButtonClicked 事件处理程序时,Note 实例会保存到数据库中,并且应用程序会导航回上一页。 执行 OnDeleteButtonClicked 事件处理程序时,Note 实例会从数据库中删除,并且应用程序会导航回上一页。

    通过按 Ctrl+S,保存对 NoteEntryPage.xaml.cs 所做的更改。

  11. 在每个平台上生成并运行项目。 有关详细信息,请参阅生成快速入门

    在 NotesPage 上,按“添加” 按钮以导航到 NoteEntryPage 并输入便笺。 保存便笺之后,应用程序会导航回 NotesPage。

    输入一些不同长度的便笺,以观察应用程序行为。 关闭应用程序并重新启动它,以确保你输入的笔记已保存到数据库。

使用 Visual Studio for Mac 更新应用

  1. 启动 Visual Studio for Mac 并打开“Notes”解决方案。

  2. 在“Solution Pad”中,右键单击“Notes”解决方案,选择“管理 NuGet 包...”:

    管理 NuGet 包

  3. 在“管理 NuGet 包”对话框中,选择“浏览”选项卡,再搜索“sqlite-net-pcl”NuGet 包 。

    警告

    许多 NuGet 包都有着类似的名称。 正确的包具有以下属性:

    尽管包的名称如此,此 NuGet 包也可以用于 .NET Standard 项目。

    在“管理 NuGet 包”对话框中,选择“sqlite-net-pcl”包,然后单击“添加包”按钮将其添加到解决方案 :

    选择 sqlite-net-pcl

    此包将用于将数据库操作合并到应用程序。

  4. 在“选择项目”对话框中,确保选中每个复选框,然后按“确定”按钮:

    将包添加到所有项目

    这会将 NuGet 包添加到解决方案中的每个项目。

  5. 在“Solution Pad”的“Notes”项目中,打开“Models”文件夹中的“Note.cs”,并将现有代码替换为以下代码:

    using System;
    using SQLite;
    
    namespace Notes.Models
    {
        public class Note
        {
            [PrimaryKey, AutoIncrement]
            public int ID { get; set; }
            public string Text { get; set; }
            public DateTime Date { get; set; }
        }
    }
    

    此类定义一个 Note 模型,该模型将在应用程序中存储有关每个便笺的数据。 使用 PrimaryKeyAutoIncrement 特性标记 ID 属性,以确保 SQLite.NET 数据库中的每个 Note 实例均具有 SQLite.NET 提供的唯一 ID。

    通过选择“文件”>“保存”(或按 ⌘ + S),保存对 Note.cs 所做的更改。

    警告

    由于在后续步骤中将修复一些错误,暂时不会生成应用程序。

  6. 在“Solution Pad”中,将名为“Data”的新文件夹添加到“Notes”项目。

  7. 在“Solution Pad”的“Notes”项目中,将名为“NoteDatabase”的新类添加到“Data”文件夹。

  8. 在 NoteDatabase.cs 中,将现有代码替换为以下代码:

    using System.Collections.Generic;
    using System.Threading.Tasks;
    using SQLite;
    using Notes.Models;
    
    namespace Notes.Data
    {
        public class NoteDatabase
        {
            readonly SQLiteAsyncConnection database;
    
            public NoteDatabase(string dbPath)
            {
                database = new SQLiteAsyncConnection(dbPath);
                database.CreateTableAsync<Note>().Wait();
            }
    
            public Task<List<Note>> GetNotesAsync()
            {
                //Get all notes.
                return database.Table<Note>().ToListAsync();
            }
    
            public Task<Note> GetNoteAsync(int id)
            {
                // Get a specific note.
                return database.Table<Note>()
                                .Where(i => i.ID == id)
                                .FirstOrDefaultAsync();
            }
    
            public Task<int> SaveNoteAsync(Note note)
            {
                if (note.ID != 0)
                {
                    // Update an existing note.
                    return database.UpdateAsync(note);
                }
                else
                {
                    // Save a new note.
                    return database.InsertAsync(note);
                }
            }
    
            public Task<int> DeleteNoteAsync(Note note)
            {
                // Delete a note.
                return database.DeleteAsync(note);
            }
        }
    }
    

    此类包含用于创建数据库、从中读取数据、向其写入数据以及从中删除数据的代码。 代码使用将数据库操作移动到后台线程的异步 SQLite.NET API。 此外,NoteDatabase 构造函数将数据库文件的路径作为参数。 在下一步中,此路径由 App 类提供。

    通过选择“文件”>“保存”(或按 ⌘ + S),保存对 NoteDatabase.cs 所做的更改。

    警告

    由于在后续步骤中将修复一些错误,暂时不会生成应用程序。

  9. 在“Solution Pad”的“Notes”项目中,展开“App.xaml”,然后双击“App.xaml.cs”将其打开 。 然后将现有代码替换为以下代码:

    using System;
    using System.IO;
    using Notes.Data;
    using Xamarin.Forms;
    
    namespace Notes
    {
        public partial class App : Application
        {
            static NoteDatabase database;
    
            // Create the database connection as a singleton.
            public static NoteDatabase Database
            {
                get
                {
                    if (database == null)
                    {
                        database = new NoteDatabase(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Notes.db3"));
                    }
                    return database;
                }
            }
    
            public App()
            {
                InitializeComponent();
                MainPage = new AppShell();
            }
    
            protected override void OnStart()
            {
            }
    
            protected override void OnSleep()
            {
            }
    
            protected override void OnResume()
            {
            }
        }
    }
    

    此代码定义一个 Database 属性,该属性以单一实例的形式创建新 NoteDatabase 实例,将数据库的文件名作为参数传入 NoteDatabase 构造函数。 以单一实例的形式公开数据库的优势是,所创建的单一数据库连接在应用程序运行时保持打开状态,因此避免了每次执行数据库操作时打开和关闭数据库文件所产生的费用。

    通过选择“文件”>“保存”(或按 ⌘ + S),保存对 App.xaml.cs 所做的更改。

    警告

    由于在后续步骤中将修复一些错误,暂时不会生成应用程序。

  10. 在“Solution Pad”的“Notes”项目中,展开“Views”文件夹中的“NotesPage.xaml”,并打开“NotesPage.xaml.cs” 。 然后将 OnAppearingOnSelectionChanged 替换为以下代码:

    protected override async void OnAppearing()
    {
        base.OnAppearing();
    
        // Retrieve all the notes from the database, and set them as the
        // data source for the CollectionView.
        collectionView.ItemsSource = await App.Database.GetNotesAsync();
    }
    
    async void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (e.CurrentSelection != null)
        {
            // Navigate to the NoteEntryPage, passing the ID as a query parameter.
            Note note = (Note)e.CurrentSelection.FirstOrDefault();
            await Shell.Current.GoToAsync($"{nameof(NoteEntryPage)}?{nameof(NoteEntryPage.ItemId)}={note.ID.ToString()}");
        }
    }    
    

    OnAppearing 方法使用存储在数据库中的任何便笺填充 CollectionViewOnSelectionChanged 方法导航到 NoteEntryPage,将所选的 Note 对象的 ID 属性作为查询参数传递。

    通过选择“文件”>“保存”(或按 ⌘ + S),保存对 NotesPage.xaml.cs 所做的更改。

    警告

    由于在后续步骤中将修复一些错误,暂时不会生成应用程序。

  11. 在“Solution Pad”中,展开“Views”文件夹中的“NoteEntryPage.xaml”,并打开“NoteEntryPage.xaml.cs” 。 然后将 LoadNoteOnSaveButtonClickedOnDeleteButtonClicked 替换为以下代码:

    async void LoadNote(string itemId)
    {
        try
        {
            int id = Convert.ToInt32(itemId);
            // Retrieve the note and set it as the BindingContext of the page.
            Note note = await App.Database.GetNoteAsync(id);
            BindingContext = note;
        }
        catch (Exception)
        {
            Console.WriteLine("Failed to load note.");
        }
    }
    
    async void OnSaveButtonClicked(object sender, EventArgs e)
    {
        var note = (Note)BindingContext;
        note.Date = DateTime.UtcNow;
        if (!string.IsNullOrWhiteSpace(note.Text))
        {
            await App.Database.SaveNoteAsync(note);
        }
    
        // Navigate backwards
        await Shell.Current.GoToAsync("..");
    }
    
    async void OnDeleteButtonClicked(object sender, EventArgs e)
    {
        var note = (Note)BindingContext;
        await App.Database.DeleteNoteAsync(note);
    
        // Navigate backwards
        await Shell.Current.GoToAsync("..");
    }
    

    NoteEntryPage使用 LoadNote 方法从数据库中检索注释(其 ID 已作为查询参数传递到页面),并将其存储为页面的 BindingContext 中的 Note 对象。 执行 OnSaveButtonClicked 事件处理程序时,Note 实例会保存到数据库中,并且应用程序会导航回上一页。 执行 OnDeleteButtonClicked 事件处理程序时,Note 实例会从数据库中删除,并且应用程序会导航回上一页。

    通过选择“文件”>“保存”(或按 ⌘ + S),保存对 NoteEntryPage.xaml.cs 所做的更改。

  12. 在每个平台上生成并运行项目。 有关详细信息,请参阅生成快速入门

    在 NotesPage 上,按“添加” 按钮以导航到 NoteEntryPage 并输入便笺。 保存便笺之后,应用程序会导航回 NotesPage。

    输入一些不同长度的便笺,以观察应用程序行为。 关闭应用程序并重新启动它,以确保你输入的笔记已保存到数据库。

后续步骤

在此快速入门中,读者学习了如何:

  • 在本地将数据存储在 SQLite.NET 数据库中。

继续学习下一个快速入门教程,使用 XAML 样式为应用程序设置样式。