练习:使用 SQLite 在本地存储数据

已完成

在本练习中,你将使用 SQLite 在应用程序中本地存储信息。 在示例场景中,你决定缓存社交媒体应用的数据以改善响应能力。 本练习将创建并使用一个本地 SQLite 数据库来存储有关人员的信息。 你将在本地存储中保存物理数据库文件。

本模块使用 .NET 8.0 SDK。 通过在首选命令终端中运行以下命令,确保你已安装 .NET 8.0:

dotnet --list-sdks

将显示类似于以下示例的输出:

6.0.317 [C:\Program Files\dotnet\sdk]
7.0.401 [C:\Program Files\dotnet\sdk]
8.0.100 [C:\Program Files\dotnet\sdk]

确保列出了以 8 开头的版本。 如果未列出任何版本或未找到命令,请安装最新的 .NET 8.0 SDK

打开初学者解决方案

  1. 克隆或下载练习存储库

    注意

    最好将练习内容克隆到较短的文件夹路径,例如 C:\dev,以避免生成进程生成的文件超过最大路径长度。

  2. 使用 Visual Studio 打开 People.sln 解决方案,可在“mslearn-dotnetmaui-store-local-data”>“人员”或 Visual Studio Code 的初学者文件夹中找到该解决方案

    注意

    暂时不要尝试生成解决方案。 代码并不完整,在你添加缺少的元素(稍后将在本练习中执行此操作)之前代码不会编译。

定义 SQLite 实体

  1. 右键单击“人员”项目,选择“添加”,然后选择“新建文件夹”以向项目添加新文件夹。 将新文件夹命名为“Models”

  2. 右键单击“Models”文件夹,选择“添加”,然后选择“类”。 确保在列表中选中“类”,然后将新类命名为“Person.cs”。 选择添加

  3. 修改该类并将其标记为 public

    namespace People.Models;
    
    public class Person
    {
    }
    
  4. 将名为 Idint 属性添加到 Person 类。

  5. 添加名为 Namestring 属性。 此类应如下所示:

    namespace People.Models;
    
    public class Person
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
    
  6. 保存 Person.cs 文件

添加 SQLite 库

  1. 在 Visual Studio 的“解决方案资源管理器”中右键单击“People”项目节点

  2. 在显示的上下文菜单中,选择“管理 NuGet 包”

  3. 搜索并选择“sqlite-net-pcl”,然后选择“安装”

    A screenshot showing the NuGet package manager with the sqlite-net-pcl library selected.

  4. 此外,搜索并选择“SQLitePCLRaw.bundle_green”,然后选择“安装”

如果使用 Visual Studio Code,请使用以下命令打开终端和这些包:

dotnet add package sqlite-net-pcl
dotnet add package SQLitePCLRaw.bundle_green

添加 SQLite 属性

  1. 在 Person.cs 文件中,将 SQLite 命名空间的 using 指令添加到 Person 类的文件。 借助此指令,可使用 SQLite 特性。

    using SQLite;
    
    namespace People.Models;
    
    public class Person
    {
        ...
    }
    
  2. 使用 [Table] 特性对 Person 类进行批注,并将表名指定为 people

  3. Id 属性指定为主键。 使用 [PrimaryKey][AutoIncrement] 特性对其进行批注。

  4. Name 属性添加注释。 将其 MaxLength 指定为 250。 指定列中的每个值都应为 Unique

    完成的类应如下所示:

    using SQLite;
    
    namespace People.Models;
    
    [Table("people")]
    public class Person
    {
        [PrimaryKey, AutoIncrement]
        public int Id { get; set; }
    
        [MaxLength(250), Unique]
        public string Name { get; set; }
    }
    
  5. 保存 Person.cs 文件

连接到数据库

  1. 打开 PersonRepository.cs 文件

  2. 检查 PersonRepository 类。 此类包含带 TODO 标记的不完整主干代码,你将在其中添加用于访问数据库的功能。

  3. SQLitePeople.Models 命名空间的 using 指令添加到 PersonRepository.cs 类的文件。

  4. 将名为 conn 的专用 SQLiteConnection 字段添加到 Init 函数上方的类。

  5. Init 函数中,检查 conn 是否不等于 null。 如果是,则立即返回。

    if (conn != null)
        return;
    

    这样,SQLite 数据库的初始化代码仅运行一次。

  6. 使用 _dbPath 变量初始化 conn 字段以连接到数据库。

  7. 使用 conn.CreateTable 方法创建一个表以存储 Person 数据。 完成的 Init 函数应如下所示:

    using SQLite;
    using People.Models;
    ...
    
    private SQLiteConnection conn;
    ...
    private void Init()
    {
       if (conn != null)
          return;
    
       conn = new SQLiteConnection(_dbPath);
       conn.CreateTable<Person>();
    }
    

向数据库中插入行

  1. PersonRepository 类中找到 AddNewPerson 方法。

  2. 将此方法中的 TODO 注释替换为用于插入新 Person 对象的代码。 代码首先调用 Init 以验证数据库已初始化,然后使用 SQLiteConnection 对象的 Insert 方法。 将 result 变量设置为 Insert 方法返回的值,如以下代码所示:

    public void AddNewPerson(string name)
    {
        int result = 0;
        try
        {
            // enter this line
            Init();
    
            // basic validation to ensure a name was entered
            if (string.IsNullOrEmpty(name))
                throw new Exception("Valid name required");
    
            // enter this line
            result = conn.Insert(new Person { Name = name });
            ...
        }
        ...
    }
    

检索数据库中的行

  1. PersonRepository 类中找到 GetAllPeople 方法。

  2. 调用 Init 来验证数据库是否已初始化。

  3. 使用泛型 Table\<T> 方法检索表中的所有行。 将 Person 指定为类型参数。

  4. 使用 ToList() 扩展方法将结果转换为 List\<Person> 集合,并返回此集合。

  5. 通过将代码包装在 try-catch 块中来添加错误处理。 如果出现错误,请将 StatusMessage 属性设置为异常的 Message 属性并返回一个空集合。 完整的方法应如下所示:

    public List<Person> GetAllPeople()
    {
       try
       {
          Init();
          return conn.Table<Person>().ToList();
       }
       catch (Exception ex)
       {
          StatusMessage = string.Format("Failed to retrieve data. {0}", ex.Message);
       }
    
       return new List<Person>();
    }
    
  6. 保存 PersonRepository.cs 文件

将存储库集成到 UI 中

  1. 打开 MauiProgram.cs 文件

  2. CreateMauiApp 函数中用于将 MainPage 页面作为单一实例服务添加到应用的语句后面,添加用于执行以下任务的代码:

    • 创建名为 dbPath 的字符串变量。 使用表达式 FileAccessHelper.GetLocalFilePath("people.db3") 初始化此字符串。 应用使用的数据库文件名为 people.db3,应用会将此文件保存在设备上的本地存储中

    • 使用依赖项注入将 PersonRepository 类作为单一实例服务添加到应用。 PersonRepository 类公开一个构造函数,该构造函数将数据库文件的路径用作字符串参数。

    CreateMauiApp 函数的已完成代码应如下所示:

    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiApp<App>()
            .ConfigureFonts(fonts =>
            {
                fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
                fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
            });
    
        // Add this code
        string dbPath = FileAccessHelper.GetLocalFilePath("people.db3");
        builder.Services.AddSingleton<PersonRepository>(s => ActivatorUtilities.CreateInstance<PersonRepository>(s, dbPath));
    
        return builder.Build();
    }
    
  3. 保存 MauiProgram.cs 文件

  4. 在解决方案资源管理器中展开“App.xaml”,然后打开 App.xaml.cs 文件

  5. 添加名为 PersonRepopublic, static 属性,将 PersonRepository 对象保存到 App 类。

  6. 通过将 PersonRepository 参数添加到构造函数并将“PersonRepo”属性设置为此参数中的值,初始化构造函数中的 PersonRepo 属性。 完成的 App 类应如下所示:

    public partial class App : Application
    {
        public static PersonRepository PersonRepo { get; private set; }
    
        public App(PersonRepository repo)
        {
            InitializeComponent();
    
            MainPage = new AppShell();
    
            PersonRepo = repo;
        }
    }
    

注意

依赖项注入过程自动将 repo 参数填充到构造函数。

测试应用程序

  1. 使用 CTRL+Shift+B 生成解决方案,并使用 F5 开始调试。 UI 出现时,请输入你的姓名并选择“添加人员”

    A screenshot of the app with a successful message stating a record has been added.

  2. 选择“获取所有人员”,然后检查你的姓名是否出现

    A screenshot of the app with a list of all the records in the database.

  3. 通过添加更多姓名并检索存储的人员列表进行试验。

  4. 返回到 Visual Studio 或 Visual Studio Code,并使用 Shift+F5 停止调试。

  5. 重启应用并选择“获取所有人员”。 检查先前存储的姓名是否仍然存储在数据库中。 完成后关闭应用。