首页 > 编程语言 >Asp-Net-Core开发笔记:快速在已有项目中引入EFCore

Asp-Net-Core开发笔记:快速在已有项目中引入EFCore

时间:2023-10-08 17:23:04浏览次数:52  
标签:Core Asp StarBlog 数据库 public EFCore Data builder

前言

很多项目一开始选型的时候没有选择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 环境,把每一行命令末尾的反引号换成 \ 即可。

参考资料

标签:Core,Asp,StarBlog,数据库,public,EFCore,Data,builder
From: https://www.cnblogs.com/deali/p/17749676.html

相关文章

  • .net core读取Response.Body
    读取请求体流的demopublicstaticasyncTask<string>GetBodyForm(thisHttpContexthttp){varcontent=string.Empty;varrequest=http.Request;try{request.Body.Position=......
  • NetCore Ocelot 之 Rate Limiting
    Ocelotsupportsratelimitingofupstreamrequestssothatyourdownstreamservicesdonotbecomeoverloaded.OKsotogetratelimitingworkingforaRouteyouneedtoaddthefollowingjsontoit."RateLimitOptions":{"ClientWhi......
  • Jasper模板使用记录十——控制元素显示
    控制元素显示PrintWhenExpression1.通过设置PrintWhenExpression属性,来控制元素是否显示2.PrintWhenExpression应设置为一个表达式,表达式的结果为布尔类型的值,值为true时显示元素3.表达式使用java语法(此语法与模板的属性language有关)即可,如$F{flag}.equals("1")、$F{f......
  • Jasper模板使用记录九——detail整行换页
    问题当detail中的某行数据过长,高度拉伸之后,导致一行数据在两页中各显示一部分解决办法设置detail的SplitType属性为Prevent,就可以使整行数据在下一页显示......
  • EFCore 使用FluntApi配置 全局查询筛选器
    我们在类中通常会有一个属性为IsDel来表示软删除或也称逻辑删除,这个属性会导致我们在进行查询操作时,每一次都要.where(s=>s.IsDel==false)非常的麻烦。在使用efCore时可用通过配置查询筛选器来很好的解决这个问题。publicclassSysUser{publiclongId{get;set;}publi......
  • Jasper模板使用记录八——背景实现整页边框
    背景Background实现整页边框1.使背景元素的大小与页面纸张大小一致,然后在背景元素上的添加的元素都会显示在页面的相应位置上2.这样就只需要在背景元素上添加一个矩形框,就可以作为整页的边框了<background> <bandheight="800"splitType="Stretch"> <propertyname="com......
  • EF Core模型设置主键自增
    提问如何EFCore模型设置主键自增回答Microsoft.AspNetCore.Identity.EntityFrameworkCore[Key][DatabaseGenerated(DatabaseGeneratedOption.Identity)]publicintID{get;set;}参考https://www.quarkbook.com/?p=561https://learn.microsoft.com/zh-cn/ef/core/mo......
  • Mysql实现EF Core CodeFirst实现
    一、引用包Microsoft.EntityFrameworkCore.ToolsPomelo.EntityFrameworkCore.MySql二、常用命令1、Add-Migration(版本号)创建新的CodeFirst文件2、Update-Database更新数据库三、代码实现///<summary>///系统用户///</summary>[Table("SysU......
  • C#集成ViewFaceCore人脸检测识别库
    前言#人脸检测与识别现在已经很成熟了,C#上有ViewFaceCore这个很方便的库,但这种涉及到native调用的库,一般会有一些坑,本文记录一下开发和部署的过程。本文的项目是AIHub,关于本项目的开发过程,可以参考之前的文章:项目完成小结:使用Blazor和gRPC开发大模型客户端而且经过最近......
  • NetCore学习笔记:单元测试和集成测试
    前言#我在使用AspNetCore的这段时间内,看了很多开源项目和博客,发现各种.Net体系的新技术很多人都有关注和使用,但却很少有人关注测试。测试是软件生命周期中的一个非常重要的阶段,对于保证软件的可靠性具有极其重要的意义。在应用程序的开发过程中,为了确保它的功能与预期一致,......