UWP开发之ORM实践:如何使用Entity Framework Core做SQLite数据持久层?

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

时间: 2024-10-25 19:52:30

UWP开发之ORM实践:如何使用Entity Framework Core做SQLite数据持久层?的相关文章

UWP开发之Template10实践二:拍照功能你合理使用了吗?(TempState临时目录问题)

最近在忙Asp.Net MVC开发一直没空更新UWP这块,不过有时间的话还是需要将自己的经验和大家分享下,以求共同进步. 在上章[UWP开发之Template10实践:本地文件与照相机文件操作的MVVM实例(图文付原代码)]已经谈到了使用FileOpenPicker进行文件选择,以及CameraCaptureUI进行拍照. 对于文件选择一般进行如下设置就能实现: // 选择多个文件 FileOpenPicker openPicker = new FileOpenPicker(); openPic

UWP开发之Mvvmlight实践七:寻找Mobile模拟器或者实体机中Packages文件夹小技巧

在开发中或者后期测试乃至最后交付使用的时候,如果应用出问题了我们一般的做法就是查看Log文件.上章也提到了查看Log文件,这章重点讲解下如何查看Log文件?如何找到我们需要的Packages安装包目录? 桌面系统应用 安装在桌面系统上的应用,我们是很容易就可以找到安装包的目录. 目录结构:C:\Users\{用户名}\AppData\Local\Packages\{UWP应用包名}\ {用户名}=系统登录用户名,{UWP应用包名}=UWP应用打包时的名称. 比如查看[UWP开发之Mvvmligh

UWP开发之Mvvmlight实践九:基于MVVM的项目架构分享

在前几章介绍了不少MVVM以及Mvvmlight实例,那实际企业开发中将以那种架构开发比较好?怎样分层开发才能节省成本? 本文特别分享实际企业项目开发中使用过的项目架构,欢迎参照使用!有不好的地方欢迎指点! 基于MVVM的UWP项目架构 每个项目或者目录下需要什么文件如下图所示: 项目参照关系: 备注:如果使用Entity Framework Core做ORM持久层,只需要将UA.DataAccess层做替换就可以.希望本文能对您的团队开发带来一定功效.

UWP开发之Mvvmlight实践四:{x:bind}和{Binding}区别详解

{x:bind}是随着UWP被推出而被添加的,可以说是Win10 UWP开发专有扩展.虽然 {x:Bind} 缺少{Binding} 中的一些功能,但它运行时所花费的时间和使用的内存量均比 {Binding} 要少,且支持更好的调试. 参照网址:{x:Bind} 标记扩展,GitHub微软UWP实例之XamlBind 1,{x:Bind} 基本原理 在 XAML 加载时,{x:Bind} 将转换为你所需的绑定对象,此对象将从数据源上的某一属性中获取相关值.绑定对象可以配置为观察数据源属性值的更改

UWP开发之Mvvmlight实践五:SuspensionManager中断挂起以及复原处理

最近比较忙有一段时间没有更新了,再接再厉继续分享. 先我们看看App在生命周期中会出现那些状态: 详细介绍参考官网:App lifecycle  https://msdn.microsoft.com/en-us/windows/uwp/launch-resume/app-lifecycle 一般情况: 比如用新闻APP看新闻的时候突然收到邮件,然后跳转到邮件APP查看邮件,查看完了再回到APP继续看新闻. 这个时候如果不做中断挂起处理的话,是很难保证APP会恢复到跳转之前的状态.之所以说很难保证

UWP开发之Mvvmlight实践六:MissingMetadataException解决办法(.Net Native下Default.rd.xml配置问题)

最近完成一款UWP应用,在手机端测试发布版(Release)的时候应用莫名奇妙的强行关闭,而同样的应用包在PC端一点问题都没有,而且Debug版在两个平台都没有问题,唯独手机的Release版有问题.实在没办法只能记录每个步骤的Log,通过查看Log发现是SuspensionManager的DataContractSerializer序列化抛出了ArgumentNullException异常. 常见.NET Native引发异常: 例1: System.InvalidCastException:

[UWP小白日记-11]在UWP中使用Entity Framework Core(Entity Framework 7)操作SQLite数据库(一)

前言 本文中,您将创建一个通用应用程序(UWP),使用Entity Framework Core(Entity Framework 7)框架在SQLite数据库上执行基本的数据访问. 准备: Entity Framework Core(Entity Framework 7)下文将简称:EF 1.在UWP中使用EF需要更新Microsoft.NETCore.UniversalWindowsPlatform到大于“5.2.2”的版本. 2.直接在“程序包管理器控制台”输入命令来更新:Update-P

基于.NET的微软ORM框架视频教程(Entity Framework技术)

基于.NET的微软ORM框架视频教程(Entity Framework技术) 第一讲  ORM映射 第二讲 初识EntifyFramework框架 第三讲 LINQ表达式查询 第四讲 LINQ方法查询 第五讲 LINQ TO Entities 第六讲 ObjectQuery查询(上) 第七讲 ObjectQuery查询(下) 第八讲 Entity中的增删改及事务处理 第九讲 Entity中的存储过程使用(完) 源代码及视频

001 Entity Framework Core 2.x P1

001 Entity Framework Core 2.x P1 EF Core 概述: Entity Framework Core 简介 创建Model 与数据库交互 关系数据 在ASP.NET Core中的应用 EF Core 是什么? EF Core是微软官方开发的一款ORM框架. EFCore原理 EF Core 相对于其他ORM的优势在于可以大大的提高生产力,并且,由于是微软自己的产品,所以和.Net Core的结合也会非常的好,可以提供开发者的工作效率,但是相应的, EFCore 的