選擇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");
} } }
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處理。總的來說使用很方便,節省不少工作量。