开发软件的过程中,对于本地数据库的选择通常是 SQLite ,因为它的配置相对简单,并且不需要额外的数据库服务。SQLite 可以很好的支持关系型数据库所具备的一些基本特征,如标准 SQL 语法、事物、数据表和索引等,且占用资源较少,还可在移动设备上轻松使用。

此外,Entity Framework 的一些特性(如 Fluent API、Migration 等)可以让我们其非常方便的操作 SQLite ,并且,它的开发团队还在持续项目的迭代,这些方面都能够成为我们使用 EF Core 的原因。

使用过程

1.在创建好的 WPF 程序中安装 Entity Framework 和对 SQLite 的相关支持

// Entity Framework
Install-Package Microsoft.EntityFrameworkCore.Sqlite
// 提供了用于 Migration 的工具
Install-Package Microsoft.EntityFrameworkCore.Tools

2.创建数据库访问上下文

public class User
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { set; get; }
    [MaxLength(50), Required]
    public string Name { set; get; }

    public string Age { set; get; }

    public string Sex { get; set; }
}
public class LovePlayerContext : DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlite("Data Source=ZDY.LovePlayer.db");
    }

    public DbSet<User> User { set; get; }
}

3.生成数据迁移类文件

打开 Visual Studio 程序管理包控制台,输入:

Add-Migration Migration_001

首次运行时,程序将自动生成 Migrations 目录,并向 Migrations 目录下的项目添加以下三个文件:

  • XXXXXXXXXXXXXX_Migration_001.cs - 主迁移文件 。 包含应用迁移所需的操作(在 Up() 中)和还原迁移所需的操作(在 Down() 中)。
  • XXXXXXXXXXXXXX_Migration_001.Designer.cs - 迁移元数据文件 。 包含 EF 所用的信息。
  • LovePlayerContextModelSnapshot.cs--当前模型的快照。 用于确定添加下一迁移时的更改内容。

其中,XXXXXXXXXXXXXX 为按执行时间生成的时间戳,文件名中的时间戳有助于保持文件按时间顺序排列,以便你可以查看更改进展。

当数据库模型发生改变时,需再次运行此命令生成新的 迁移

4.在 WPF 项目中调用

App.xaml.cs

public App()
{
    using (var db = new LovePlayerContext())
    {
        try
        {
            using (var context = new LovePlayerContext())
            {
                // 检查是否有新的迁移
                if (context.Database.GetPendingMigrations().Any())
                {
                    context.Database.Migrate(); //执行迁移
                }
            }
        }
        catch (NotSupportedException ex)
        {
        }
        catch (Exception ex)
        {
        }
    }
}

通过调用 context.Database.Migrate() 方法,将数据库结构同步至数据中,其中,当数据库文件不存在时,它将自动创建。

注意,请勿在 Migrate() 前调用 EnsureCreated()EnsureCreated() 会绕过迁移创建架构,这会导致 Migrate() 失败。

EnsureCreated()Migrate() 的区别:EnsureCreated() 在数据库不存在的时候也会自动创建,但如果数据库存在且数据结构有更改时,之后的更改将不会更新到数据库中。

5.测试效果

MainWindow.xaml.cs

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        this.Loaded += MainWindow_Loaded;
    }

    private void MainWindow_Loaded(object sender, RoutedEventArgs e)
    {
        using (var context = new LovePlayerContext())
        {
            if (context.User.ToList().Count == 0)
            {
                var cate1 = new User { Name = "User A" };
                var cate2 = new User { Name = "User B" };
                context.User.AddRange(cate1, cate2);
                context.SaveChanges();
            }

            // 查询
            var list = context.User.ToList();

            this.DataList.ItemsSource = list;
        }
    }
}

MainWindow.xaml

<Grid>
    <DataGrid x:Name="DataList" AutoGenerateColumns="True"></DataGrid>
</Grid>