前言

很多项目一开始选型的时候没有选择EFCore,不过EFCore确实好用,也许由于种种原因后面还是需要用到,这时候引入EFCore也很方便。

本文以 StarBlog 为例,StarBlog 目前使用的 ORM 是 FreeSQL ,引入 EFCore 对我来说最大的好处是支持多个数据库,如果是 FreeSQL 的话,服务注册的时候是单例模式,只能连接一个数据库,如果需要使用 FreeSQL 同时连接多个数据库,需要自行做一些额外的工作。

要实现的效果是:把访问记录单独使用一个数据库来存储,并且使用 EFCore 管理。

安装工具

首先安装 EFCore 的 cli 工具

dotnet tool install --global dotnet-ef

项目架构

先来回顾一下项目架构:基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目

StarBlog
├── StarBlog.Contrib
├── StarBlog.Data
├── StarBlog.Migrate
├── StarBlog.Web
└── StarBlog.sln

为了解耦,和数据有关的代码在 StarBlog.Data 项目下,因此引入 EFCore 只需要在 StarBlog.Data 这个项目中添加依赖即可。

添加依赖

StarBlog.Data 项目中添加以下三个依赖

  • Microsoft.EntityFrameworkCore
  • Microsoft.EntityFrameworkCore.Sqlite
  • Microsoft.EntityFrameworkCore.Tools

EFCore 对 SQLite 的支持很弱(根本原因是微软提供的 SQLite 驱动功能太少),所以只适合在本地开发玩玩,实际部署还是得切换成 C/S 架构的数据库(PgSQL/MySQL/SQL Server)才行。

添加后项目的 .csproj 文件新增的依赖类似这样

<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.18" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.18" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.18">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

目前 StarBlog 还在使用 .Net6 所以我添加的 EFCore 是 6.x 版本,等后续 .Net8 正式版发布之后,我会把这个项目升级到 .Net8

创建 DbContext

DbContext 是 EFCore 与数据库交互的入口,一般一个数据库对应一个。

现在来 StarBlog.Data 项目下创建一个。

using Microsoft.EntityFrameworkCore;
using StarBlog.Data.Models; namespace StarBlog.Data; public class AppDbContext : DbContext {
public DbSet<VisitRecord> VisitRecords { get; set; } public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
}

因为只需要让 EFCore 管理访问记录,所以只需要一个 DbSet

实体类配置

然后来创建个配置,虽然也可以用 Data Annotation 来配置,但 EFCore 推荐使用 Fluent Config 方式来配置数据表和字段。

创建 StarBlog.Data/Config/VisitRecordConfig.cs 文件

public class VisitRecordConfig : IEntityTypeConfiguration<VisitRecord> {
public void Configure(EntityTypeBuilder<VisitRecord> builder) {
builder.ToTable("visit_record");
builder.HasKey(e => e.Id);
builder.Property(e => e.Ip).HasMaxLength(64);
builder.Property(e => e.RequestPath).HasMaxLength(2048);
builder.Property(e => e.RequestQueryString).HasMaxLength(2048);
builder.Property(e => e.RequestMethod).HasMaxLength(10);
builder.Property(e => e.UserAgent).HasMaxLength(1024);
}
}

主要是配置了主键和各个字段的长度。

数据类型这块 EFCore 会自动映射,具体请参考官方文档。

主键类型选择

这里插播一下题外话,关于主键类型应该如何选择。

目前主要有几种方式:

  • 自增
  • GUID
  • 自增+GUID
  • Hi/Lo

这几种方式各有优劣。

  • 自增的好处是简单,缺点是在数据库迁移或者分布式系统中容易出问题,而且高并发时插入性能较差。
  • GUID好处也是简单方便,而且也适用于分布式系统;MySQL的InnoDB引擎强制主键使用聚集索引,导致新插入的每条数据都要经历查找合适插入位置的过程,在数据量大的时候插入性能很差。
  • 自增+GUID是把自增字段作为物理主键,GUID作为逻辑主键,可以在一定程度上解决上述两种方式的问题。
  • Hi/Lo可以优化自增列的性能,但只有部分数据库支持,比如SQL Server,其他的数据库暂时还没研究。

DesignTime 配置

因为我们的项目是把 AspNetCore 和数据分离的,所以需要一个 DesignTime 配置来让 EFCore 知道如何执行迁移。

StarBlog.Data 中创建 AppDesignTimeDbContextFactory.cs 文件

public class AppDesignTimeDbContextFactory : IDesignTimeDbContextFactory<AppDbContext> {
public AppDbContext CreateDbContext(string[] args) {
var builder = new DbContextOptionsBuilder<AppDbContext>(); var connStr = Environment.GetEnvironmentVariable("CONNECTION_STRING");
if (connStr == null) {
var dbpath = Path.Combine(Environment.CurrentDirectory, "app.log.db");
connStr = $"Data Source={dbpath};";
} builder.UseSqlite(connStr);
return new AppDbContext(builder.Options);
}
}

这里从环境变量读取数据库连接字符串,如果读不到就使用默认的数据库文件。

数据库迁移

这块主要是使用两组命令

  • migrations - 用于监控数据库的修改
  • database - 将修改同步到数据库里

cd 到 StarBlog.Data 目录下,执行

dotnet ef migrations add InitialCreate -o Migrations

之后可以看到 Migrations 目录下生成了迁移的代码

如果需要指定数据库文件,可以设置环境变量。

Windows的使用:

set CONNECTION_STRING = "Data Source=app.db;"

Linux的也差不多,把 set 换成 export

export CONNECTION_STRING = "Data Source=app.db;"

运行以下命令同步到数据库

dotnet ef database update

执行之后就会在 StarBlog.Data 下生成 SQLite 数据库文件。

在AspNetCore项目里集成EFCore

先把数据库连接字符串写到配置文件 appsettings.json

{
"ConnectionStrings": {
"SQLite": "Data Source=app.db;Synchronous=Off;Cache Size=5000;",
"SQLite-Log": "Data Source=app.log.db;"
}
}

Program.cs 里注册服务

builder.Services.AddDbContext<AppDbContext>(options => {
options.UseSqlite(builder.Configuration.GetConnectionString("SQLite-Log"));
});

搞定~

db-first

从已有数据库生成实体类,一般新项目不推荐这种开发方式,不过在旧项目上使用还是比较方便的,EFCore 的 cli tool 也提供很丰富的代码生成功能。

这里提供一下例子:

  • 使用 PostgreSql 数据库,要把其中 pe_shit_data 库的所有表生成实体类
  • 生成的 DbContext 类名为 ShitDbContext
  • DbContext 类的命名空间为 PE.Data
  • 实体类放在 ShitModels 目录下,命名空间为 PE.Data.ShitModels

命令如下

dotnet ef dbcontext scaffold `
"Host=cuc.dou3.net;Database=pe_shit_data;Username=postgres;Password=passw0rd" `
Npgsql.EntityFrameworkCore.PostgreSQL `
-f `
-c ShitDbContext `
--context-dir . `
--context-namespace PE.Data `
-o ShitModels `
--namespace PE.Data.ShitModels `

这个是 powershell 的命令,如果是 Linux 环境,把每一行命令末尾的反引号换成 \ 即可。

参考资料

Asp-Net-Core开发笔记:快速在已有项目中引入EFCore的更多相关文章

  1. 如何在已有项目中引入FineUIMvc

    FineUIMvc简介 FineUIMvc 是基于 jQuery 的专业 ASP.NET MVC 控件库,其前身是基于 WebForms 的开源控件库 FineUI(历时9年120多个版本).Fine ...

  2. 在CentOS7 开发与部署 asp.net core app笔记

    原文:在CentOS7 开发与部署 asp.net core app笔记 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/lihongzhai/art ...

  3. 2月送书福利:ASP.NET Core开发实战

    大家都知道我有一个公众号“恰童鞋骚年”,在公众号2020年第一天发布的推文<2020年,请让我重新介绍我自己>中,我曾说到我会在2020年中每个月为所有关注“恰童鞋骚年”公众号的童鞋们送一 ...

  4. 【视频】使用ASP.NET Core开发GraphQL服务

    GraphQL 既是一种用于 API 的查询语言也是一个满足你数据查询的运行时. GraphQL来自Facebook,它于2012年开始开发,2015年开源. GraphQL与编程语言无关,可以使用很 ...

  5. C# -- HttpWebRequest 和 HttpWebResponse 的使用 C#编写扫雷游戏 使用IIS调试ASP.NET网站程序 WCF入门教程 ASP.Net Core开发(踩坑)指南 ASP.Net Core Razor+AdminLTE 小试牛刀 webservice创建、部署和调用 .net接收post请求并把数据转为字典格式

    C# -- HttpWebRequest 和 HttpWebResponse 的使用 C# -- HttpWebRequest 和 HttpWebResponse 的使用 结合使用HttpWebReq ...

  6. 基于ASP.Net Core开发的一套通用后台框架

    基于ASP.Net Core开发一套通用后台框架 写在前面 这是本人在学习的过程中搭建学习的框架,如果对你有所帮助那再好不过.如果您有发现错误,请告知我,我会第一时间修改. 知其然,知其所以然,并非重 ...

  7. 【新书推荐】《ASP.NET Core微服务实战:在云环境中开发、测试和部署跨平台服务》 带你走近微服务开发

    <ASP.NET Core 微服务实战>译者序:https://blog.jijiechen.com/post/aspnetcore-microservices-preface-by-tr ...

  8. 《ASP.NET Core项目开发实战入门》带你走进ASP.NET Core开发

    <ASP.NET Core项目开发实战入门>从基础到实际项目开发部署带你走进ASP.NET Core开发. ASP.NET Core项目开发实战入门是基于ASP.NET Core 3.1 ...

  9. [转]ASP.NET Core 开发-Logging 使用NLog 写日志文件

    本文转自:http://www.cnblogs.com/Leo_wl/p/5561812.html ASP.NET Core 开发-Logging 使用NLog 写日志文件. NLog 可以适用于 . ...

  10. ASP.NET Core 开发-中间件(Middleware)

    ASP.NET Core开发,开发并使用中间件(Middleware). 中间件是被组装成一个应用程序管道来处理请求和响应的软件组件. 每个组件选择是否传递给管道中的下一个组件的请求,并能之前和下一组 ...

随机推荐

  1. CKS 考试题整理 (02)-Apparmor

    Context Apparmor 已在 cluster 的工作节点 node02 上被启用.一个 Apparmor 配置文件已存在,但尚未被实施. Task 在 cluster 的工作节点 node0 ...

  2. ChatGPT小型平替之ChatGLM-6B本地化部署、接入本地知识库体验

    本文期望通过本地化部署一个基于LLM模型的应用,能让大家对构建一个完整的应用有一个基本认知.包括基本的软硬环境依赖.底层的LLM模型.中间的基础框架及最上层的展示组件,最终能达到在本地零编码体验的目的 ...

  3. Python潮流周刊#8:Python 3.13 计划将解释器提速 50%!

    你好,我是猫哥.这里每周分享优质的 Python 及通用技术内容,部分为英文,已在小标题注明.(标题取自其中一则分享,不代表全部内容都是该主题,特此声明.) 首发于我的博客:https://pytho ...

  4. Python潮流周刊#9:如何在本地部署开源大语言模型?

    你好,我是猫哥.这里每周分享优质的 Python 及通用技术内容,部分为英文,已在小标题注明.(标题取自其中一则分享,不代表全部内容都是该主题,特此声明.) 首发于我的博客:https://pytho ...

  5. 前端Vue自定义带历史记录的搜索框组件searchBar 支持搜索输入框清空 搜索历史存储记录清除

    前端Vue自定义带历史记录的搜索框组件searchBar 支持搜索输入框清空 搜索历史存储记录清除,下载完整代码请访问uni-app插件市场地址:https://ext.dcloud.net.cn/p ...

  6. Redis缓存同步1-策略介绍

    缓存数据同步策略示意图 在大多数情况下,我们通过浏览器查询到的数据都是缓存数据,如果缓存数据与数据库的数据存在较大差异的话,可能会产生比较严重的后果的.所以,我们应该也必须保证数据库数据.缓存数据的一 ...

  7. Avalonia 使用EFCore调用SQLite实现Singleton全局注册

    Avalonia 使用EFCore调用SQLite实现Singleton全局注册 本篇博客是我的开源项目TerraMours.Chat.Ava的更新的记录分享,本次更新使用EntityFrameWor ...

  8. NOIP 2023 模拟赛 20230712 C 论剑

    首先是伟大的题面 然后是数据范围 先解决1-4号数据点 1.枚举每个gcd的值p,统计一次答案,得到最小值(期望得分20) \[ans=\min_{p=2}^{\max a}\sum^n_{i=1}\ ...

  9. 使用ClamAV进行linux病毒扫描

    前言 ClamAV是一个在命令行下查毒(并非杀毒)的软件,其免费开源跨平台.ClamAV默认只能查出服务器内的病毒,但是无法清除,最多删除. 安装ClamAV yum install -y epel- ...

  10. 《Pro Git》Git基础笔记

    获取Git仓库 在已存在目录中初始化仓库 $ git init 该命令会创建一个名为.git的隐藏文件. 克隆现有的仓库 $ git clone <url> # 例如 git clone ...