选择SQLite的理由
在做UWP开发的时候我们首选的本地数据库一般都是Sqlite,我以前也不知道为啥?后来仔细研究了一下也是有原因的:
1,微软做的UWP应用大部分也是用Sqlite。或者说是微软推荐使用Sqlite吧!
2,简单!就只有一个类库没有多余的参照什么的。不像其他数据库还得做复杂配置什么的麻烦!
3,不需要数据库服务,数据服务和客户都在同一个进程里面。如下图:
4,作为存储系统它只支持一个用户一个数据实体。
5,跨平台跨结构,这个好!
Sqlite主要使用内容
如果想充分使用好Sqlite数据库,建议保存好下面两个链接
- The database connection handle
- The prepared statement object
操作上面对象主要的6个接口 - sqlite3_open()
- sqlite3_prepare()
- sqlite3_step()
- sqlite3_column()
- sqlite3_finalize()
- sqlite3_close()
SQLite数据持久层:Entity Framework Core随着Entity Framework开源在.Net开发中越来越受欢迎,包括WinFrom,Asp.net MVC开发等等。为了跨平台在6.0后就是Entity Framwork Core版本。开源地址:https://github.com/aspnet/EntityFramework。
使用Entity Framwork Core当然得有个驱动才能调用SQLite数据库,那就是SQLite的ADO.NET驱动。大概层次如下:
ORM具体实现
此处做一个显示课程列表信息的UWP做实例。源代码:https://github.com/NewBLife/UWP/tree/master/SqliteEFCoreDemo。
1,新建一个空的UWP项目叫SqliteEFCoreDemo。
2,添加包引用。
Install-Package EntityFramework.SQLite –Pre
Install-Package EntityFramework.Commands –Pre
3,创建Student和Course的Entity。
// *********************************************************************** // FileName:Course // Description: // Project: // Author:NewBLife // Created:2016/5/28 21:25:32 // Copyright (c) 2016 NewBLife,All rights reserved. // *********************************************************************** using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace SqliteEFCoreDemo.Models { /// <summary> /// 设置数据库表名 /// </summary> [Table(name: "Course")] public class Course { /// <summary> /// ID不为空设置为Required /// </summary> [Required] public string ID { get; set; } public string Name { get; set; } } }
// *********************************************************************** // FileName:Student // Description: // Project: // Author:NewBLife // Created:2016/5/28 21:23:45 // Copyright (c) 2016 NewBLife,All rights reserved. // *********************************************************************** using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace SqliteEFCoreDemo.Models { /// <summary> /// 设置数据库表名 /// </summary> [Table(name: "Student")] public class Student { /// <summary> /// ID不为空设置为Required /// </summary> [Required] public string ID { get; set; } public string Name { get; set; } public List<Course> Courses { get; set; } } }
4,创建数据库操作EfDbContext继承于Microsoft.Data.Entity.DbContext。
// *********************************************************************** // FileName:EfDbContext // Description: // Project: // Author:NewBLife // Created:2016/5/28 21:32:23 // Copyright (c) 2016 NewBLife,All rights reserved. // *********************************************************************** using Microsoft.Data.Entity; namespace SqliteEFCoreDemo.Models { public class EfDbContext : DbContext { /// <summary> /// 注意:如果Student的Model里面没有设置表名将使用Students作为表名 /// </summary> public DbSet<Student> Students { get; set; } public DbSet<Course> Courses { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { // 配置数据库名 optionsBuilder.UseSqlite("Filename=School.db");
} } }
5,编译项目(非常重要,不然有可能后续步骤出错)。
6,高级操作:创建差分文件Migration。通过查看差分文件可以判断生成的表结构或者数据是不是正确(这是Entity Framework进行CodeFirst开发的便捷之处)。
在程序包管理器中执行:add-migration initDb。将自动创建下图红色部分内容(这就是Entity Framework强大之处)。
自动生成的表结构代码如下:
using System; using Microsoft.Data.Entity; using Microsoft.Data.Entity.Infrastructure; using Microsoft.Data.Entity.Metadata; using Microsoft.Data.Entity.Migrations; using SqliteEFCoreDemo.Models; namespace SqliteEFCoreDemo.Migrations { [DbContext(typeof(EfDbContext))] partial class EfDbContextModelSnapshot : ModelSnapshot { protected override void BuildModel(ModelBuilder modelBuilder) { modelBuilder .HasAnnotation("ProductVersion", "7.0.0-rc1-16348"); modelBuilder.Entity("SqliteEFCoreDemo.Models.Course", b => { b.Property<string>("ID"); b.Property<string>("Name"); b.Property<string>("StudentID"); b.HasKey("ID"); b.HasAnnotation("Relational:TableName", "Course"); }); modelBuilder.Entity("SqliteEFCoreDemo.Models.Student", b => { b.Property<string>("ID"); b.Property<string>("Name"); b.HasKey("ID"); b.HasAnnotation("Relational:TableName", "Student"); }); modelBuilder.Entity("SqliteEFCoreDemo.Models.Course", b => { b.HasOne("SqliteEFCoreDemo.Models.Student") .WithMany() .HasForeignKey("StudentID"); }); } } }
自动生成的数据更新代码如下:
using System; using System.Collections.Generic; using Microsoft.Data.Entity.Migrations; namespace SqliteEFCoreDemo.Migrations { public partial class initDb : Migration { protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.CreateTable( name: "Student", columns: table => new { ID = table.Column<string>(nullable: false), Name = table.Column<string>(nullable: true) }, constraints: table => { table.PrimaryKey("PK_Student", x => x.ID); }); migrationBuilder.CreateTable( name: "Course", columns: table => new { ID = table.Column<string>(nullable: false), Name = table.Column<string>(nullable: true), StudentID = table.Column<string>(nullable: true) }, constraints: table => { table.PrimaryKey("PK_Course", x => x.ID); table.ForeignKey( name: "FK_Course_Student_StudentID", column: x => x.StudentID, principalTable: "Student", principalColumn: "ID", onDelete: ReferentialAction.Restrict); }); } protected override void Down(MigrationBuilder migrationBuilder) { migrationBuilder.DropTable("Course"); migrationBuilder.DropTable("Student"); } } }
每次执行Add-Migration 名称 都会根据你的Model修改创建差分的Migration文件。
7,重量级操作:在App.xaml.cs的构造方法中添加如下代码来生成真正的数据库文件。
public App() { this.InitializeComponent(); this.Suspending += OnSuspending; using (var db = new EfDbContext()) { // 将差分文件写入数据库文件 db.Database.Migrate(); } }
8,添加演示布局以及Model的绑定设置。
<Page x:Class="SqliteEFCoreDemo.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:SqliteEFCoreDemo" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:data="using:SqliteEFCoreDemo.Models" mc:Ignorable="d"> <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <RelativePanel HorizontalAlignment="Center" Margin="0,50,0,0"> <Grid Name="Header" Width="300"> <Grid.RowDefinitions> <RowDefinition Height="50"/> <RowDefinition Height="50"/> <RowDefinition Height="50"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="100"/> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions> <TextBlock Name="lblCID" Grid.Column="0" Grid.Row="0" Text="课程ID:"/> <TextBox Name="txbCId" Grid.Column="1" Grid.Row="0" Width="200"/> <TextBlock Name="lblCName" Grid.Column="0" Grid.Row="1" Text="课程名称:"/> <TextBox Name="txbCName" Width="200" Grid.Column="1" Grid.Row="1" /> <Button Name="btnAdd" Grid.Column="1" Grid.Row="2" Width="100" Click="btnAdd_Click" Content="Add Course"/> </Grid> <Grid Name="List" RelativePanel.Below="Header"> <ListView Name="lstCourse"> <ListView.ItemTemplate> <DataTemplate x:DataType="data:Course"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="100"/> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions> <TextBlock Grid.Column="0" Text="{x:Bind ID,Mode=OneWay}"/> <TextBlock Grid.Column="1" Text="{x:Bind Name,Mode=OneWay}"/> </Grid> </DataTemplate> </ListView.ItemTemplate> </ListView> </Grid> </RelativePanel> </Grid> </Page>
using System.Linq; using SqliteEFCoreDemo.Models; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; //“空白页”项模板在 http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409 上有介绍 namespace SqliteEFCoreDemo { /// <summary> /// 可用于自身或导航至 Frame 内部的空白页。 /// </summary> public sealed partial class MainPage : Page { public MainPage() { this.InitializeComponent(); this.Loaded += MainPage_Loaded; } private void MainPage_Loaded(object sender, RoutedEventArgs e) { using (var db = new EfDbContext()) { lstCourse.ItemsSource = db.Courses.ToList(); } } private void btnAdd_Click(object sender, RoutedEventArgs e) { using (var db = new EfDbContext()) { var newCourse = new Course { ID = txbCId.Text.Trim(), Name = txbCName.Text.Trim() }; txbCId.Text = string.Empty; txbCName.Text = string.Empty; db.Courses.Add(newCourse); db.SaveChanges(); lstCourse.ItemsSource = db.Courses.ToList(); } } } }
9,启动应用,添加数据试试。
10,查看自动创建的数据库文件。
Not Null设置,外键设置等等都自动设置好了!好强大有没有…
总结
用EFCore做数据库持久层只需要面向对象模型做处理就可以,与数据模型的交互等交给Entity Framework Core处理。总的来说使用很方便,节省不少工作量。