UWP開發之ORM實踐:如何使用Entity Framework Core做SQLite數據持久層?


選擇SQLite的理由

在做UWP開發的時候我們首選的本地數據庫一般都是Sqlite,我以前也不知道為啥?后來仔細研究了一下也是有原因的:

1,微軟做的UWP應用大部分也是用Sqlite。或者說是微軟推薦使用Sqlite吧!

2,簡單!就只有一個類庫沒有多余的參照什么的。不像其他數據庫還得做復雜配置什么的麻煩!

3,不需要數據庫服務,數據服務和客戶都在同一個進程里面。如下圖:

1_SQLite

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驅動。大概層次如下:

    2_SQLite

     

    ORM具體實現

    此處做一個顯示課程列表信息的UWP做實例。源代碼:https://github.com/NewBLife/UWP/tree/master/SqliteEFCoreDemo

    1,新建一個空的UWP項目叫SqliteEFCoreDemo。

    2,添加包引用。

    Install-Package EntityFramework.SQLite –Pre

    Install-Package EntityFramework.Commands –Pre

    image

    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強大之處)。

    image

     

     

    自動生成的表結構代碼如下:

    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,啟動應用,添加數據試試。

    image

     

    10,查看自動創建的數據庫文件。

    Not Null設置,外鍵設置等等都自動設置好了!好強大有沒有…

    image

     

    總結

    用EFCore做數據庫持久層只需要面向對象模型做處理就可以,與數據模型的交互等交給Entity Framework Core處理。總的來說使用很方便,節省不少工作量。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM