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

已完成

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

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

dotnet --list-sdks

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

8.0.100 [C:\Program Files\dotnet\sdk]
9.0.100 [C:\Program Files\dotnet\sdk]

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

打开初学者解决方案

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

    注意

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

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

    注意

    暂时不要尝试运行应用程序,代码不完整,并且会引发异常,请根据本练习的后面部分添加缺少的元素之后再运行。

定义 SQLite 实体

  1. 在“Models”文件夹中打开“Person.cs”文件

  2. 将名为 Idint 属性添加到 Person 类。

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

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

添加 SQLite 库

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

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

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

    显示 NuGet 包管理器的屏幕截图,其中选择了 sqlite-net-pcl 库。

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

dotnet add package sqlite-net-pcl

添加 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 属性。 此属性将保存 App 类的 PersonRepository 对象。

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

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

注意

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

测试应用程序

  1. Ctrl+Shift+B 生成解决方案。

  2. 生成完成后,按 F5 开始调试。 UI 出现时,请输入你的姓名并选择“添加人员”

    应用的屏幕截图,其中显示了一条表示已成功添加记录的消息。

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

    应用的屏幕截图,其中列出了数据库中的所有记录。

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

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

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