• 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处理。总的来说使用很方便,节省不少工作量。

  • 相关阅读:
    Shell 编程基础之 Until 练习
    Shell 编程基础之 While 练习
    Shell 编程基础之 For 练习
    Shell 编程基础之 If 练习
    Kafka 0.8 Controller设计机制和状态变化
    5 Kafka 应用问题经验积累
    3 Kafka两个版本在Zookeeper的元数据存储
    Broker流量均衡 prefer reassign
    Kafka 0.8 Consumer Rebalance
    2 Kafka Broker
  • 原文地址:https://www.cnblogs.com/lixiaobin/p/UWPEFCORM.html
Copyright © 2020-2023  润新知