EF Core 在实际开发中,如何分层?

image

前言:什么是分层?

  1. 分层就是将 EF Core 放在单独的项目中,其它项目如 Asp.net core webapi 项目引用它
  2. 这样的好处是解耦和项目职责的清晰划分,并且可以重用 EF Core 项目
  3. 但是也会数据库迁移变得复杂起来

Step by step 步骤

  1. 创建一个 .NET 类库项目,项目名字为 BooksEFCore

  2. 引用以下 Nuget 包

    Microsoft.EntityFrameworkCore.Relational
    Microsoft.EntityFrameworkCore.SqlServer
    Microsoft.EntityFrameworkCore.Tools

  3. 创建实体类 Book

    // 把Book类声明为一个记录类,而不是普通的类,主要是为了让编译器自动生成ToString方法,简化对象的输出
    public record Book
    {
    	public Guid Id { get; set; }
    	public string Name { get; set; }
    	public double Price { get; set; }
    }
    
  4. 配置实体类

    using Microsoft.EntityFrameworkCore;
    using Microsoft.EntityFrameworkCore.Metadata.Builders;
    
    class BookConfig : IEntityTypeConfiguration<Book>
    {
    	public void Configure(EntityTypeBuilder<Book> builder)
    	{
    		builder.ToTable("T_Books2");
    	}
    }	
    
  5. 创建上下文类【注意,这里有跟单体 EF Core 项目不一样的地方,看注释

    using Microsoft.EntityFrameworkCore;
    
    public class MyDbContext:DbContext
    {
    	public DbSet<Book> Books { get; set; }
    
    	//注意:
    	//在运行时通过读取配置来确定要连接的数据库
    	//不再重写 OnConfiguring 方法和在其中调用 UseSqlServer 等方法来设置要使用的数据库
    	//为 MyDbContext 类增加了 DbContextOptions<MyDbContext> 类型参数的构造方法
    	//DbContextOptions 是一个数据库连接配置对象,在 ASP.NET Core 项目中提供对 DbContextOptions 的配置
    	public MyDbContext(DbContextOptions<MyDbContext> options) : base(options)
    	{
    
    	}
    
    	
    	protected override void OnModelCreating(ModelBuilder modelBuilder)
    	{
    		base.OnModelCreating(modelBuilder);
    		modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly);
    	}
    }	
    
  6. 创建一个 Asp.net core webapi 项目,命名为 “EFCore测试用WebAPI项目1”

  7. 引用 EF Core 类项目 BooksEFCore

  8. 打开 appsettings.json 文件并添加数据库连接字符串配置

    {
      "Logging": {
    	"LogLevel": {
    	  "Default": "Information",
    	  "Microsoft.AspNetCore": "Warning"
    	}
      },
      "AllowedHosts": "*",
      "ConnectionStrings": {
    	"Default": "Server=(localdb)\\mssqllocaldb;Database=TestDB;Trusted_Connection=True;MultipleActiveResultSets=true"
      }
    }	
    
  9. 打开 Program.cs 文件,注册数据库上下文服务

    using Microsoft.EntityFrameworkCore;
    
    var builder = WebApplication.CreateBuilder(args);
    
    // Add services to the container.
    
    builder.Services.AddControllers();
    // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
    builder.Services.AddEndpointsApiExplorer();
    builder.Services.AddSwaggerGen();
    
    // 注册数据库上下文服务
    // 使用AddDbContext方法来通过依赖注入的方式让MyDbContext采用指定的连接字符串连接数据库。
    // 由于AddDbContext方法是泛型的,因此可以为同一个项目中的多个不同的上下文设定连接不同的数据库。
    builder.Services.AddDbContext<MyDbContext>(opt =>
    {
    	string connStr = builder.Configuration.GetConnectionString("Default")!;
    	opt.UseSqlServer(connStr);
    });
    
    var app = builder.Build();
    
    // Configure the HTTP request pipeline.
    if (app.Environment.IsDevelopment())
    {
    	app.UseSwagger();
    	app.UseSwaggerUI();
    }
    
    app.UseHttpsRedirection();
    
    app.UseAuthorization();
    
    app.MapControllers();
    
    app.Run();	
    
  10. 创建 TestController 控制器,编写数据库读写的测试代码

    using Microsoft.AspNetCore.Mvc;
    
    [ApiController]
    [Route("[controller]/[action]")]
    public class TestController : ControllerBase
    {
    	private readonly MyDbContext dbCtx;
    
    	/// <summary>
    	/// 用依赖注入的形式来创建上下文
    	/// </summary>
    	/// <param name="dbCtx"></param>
    	public TestController(MyDbContext dbCtx)
    	{
    		this.dbCtx = dbCtx;
    	}
    
    	[HttpPost]
    	public async Task<long> Save()
    	{
    		dbCtx.Add(new Book { Id = Guid.NewGuid(), Name = "零基础趣学C语言", Price = 59 });
    		await dbCtx.SaveChangesAsync();
    		return dbCtx.Books.LongCount();
    	}
    }
    
  11. 生成实体类的迁移脚本

    1. 回到 EF Core 类项目 BooksEFCore

    2. 新建一个实现 IDesignTimeDbContextFactory 接口的类 MyDesignTimeDbContextFactory

      using Microsoft.EntityFrameworkCore;
      using Microsoft.EntityFrameworkCore.Design;
      
      //在多项目的环境下执行 EF Core 的数据库迁移有很多特殊的要求
      //容易出错,因为数据库连接在其它项目中
      //可以通过 IDesignTimeDbContextFactory 接口来解决这个问题
      //当项目中存在一个 IDesignTimeDbContextFactory 接口的实现类的时候,
      //数据库迁移工具就会调用这个实现类的 CreateDbContext 方法来获取上下文对象,
      //然后迁移工具会使用这个上下文对象来连接数据库
      //此代码只用于开发环境
      //生产环境可以去掉此代码
      class MyDesignTimeDbContextFactory : IDesignTimeDbContextFactory<MyDbContext>
      {
      	public MyDbContext CreateDbContext(string[] args)
      	{
      		DbContextOptionsBuilder<MyDbContext> builder = new();
      		string connStr = "Server=(localdb)\\mssqllocaldb;Database=TestDB;Trusted_Connection=True;MultipleActiveResultSets=true";
      		//也可以从环境变量或者其它配置文件中读取,如下:
      		//string connStr = Environment.GetEnvironmentVariable("ConnectionStrings:BooksEFCore");
      		builder.UseSqlServer(connStr);
      		return new MyDbContext(builder.Options);
      	}
      }
      
    3. 设置 BooksEFCore 为启动项目

    4. 打开 菜单-工具-Nuget包管理-程序包管理器控制台,并选中 BooksEFCore

    5. 执行 Add-Migration Init 命令生成数据库迁移脚本

    6. 然后执行 Update-database 命令即可完成数据库的创建

扩展

  1. 在进行项目开发时,推荐采用 “小上下文” 策略
  2. “小上下文” 策略特点是:
    • 把关系紧密的实体类放到同一个上下文类中,把关系不紧密的实体类放到不同的上下文类中
    • 也就是项目中存在多个上下文类,每个上下文类中只有少数几个实体类
    • 有点 DDD 的味道
  3. “小上下文” 策略的好处:
    • 一个上下文实例初始化的时候,实体类的配置等过程将非常快,其不会成为性能瓶颈
    • 如果启用了数据库连接池,数据库连接的创建也不会成为性能瓶颈。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/308110.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

linux 安装 reids并使用Windows测试结果

要安装两个软件 Windows端安装下面的软件连接虚拟机中的redis Another Redis DeskTop Manager 安装和使用_another redis desktop怎么连接-CSDN博客 redis安装 查找可用版本 选择安装最多点赞的一个 安装完成后创建redis容器 docker run -t --name redis -p 6379:6379 -d r…

这6个设计小白学习网站,海量免费学习教程!

划到最后“阅读原文”——领取工具包&#xff08;超过1000工具&#xff0c;免费素材网站分享和行业报告&#xff09; Hi&#xff0c;我是胡猛夫~&#xff0c;专注于分享各类价值网站、高效工具&#xff01; ​更多资源&#xff0c;更多内容&#xff0c;欢迎交流&#xff01;公…

3d模型显示不出来?3d不显示全模型---模大狮模型网

如果3D模型在显示时不完整或者无法显示&#xff0c;可能有几个原因导致&#xff1a; 缩放问题&#xff1a;检查一下模型的缩放是否正确。有时候模型的缩放比例可能非常大或非常小&#xff0c;导致模型无法正确显示。尝试调整模型的缩放值&#xff0c;使其适合场景。 材质问题&…

主食冻干哪款好?十大放心主食冻干名单推荐

作为养猫的人&#xff0c;我们都知道每天最担心的事情就是如何为心爱的猫咪选择一款高品质的猫粮。我们都希望为猫咪提供最好的营养&#xff0c;让它们健康快乐地成长。然而&#xff0c;近期的一些事件&#xff0c;如百利猫粮生虫和VE主食冻干掰开有虫&#xff0c;让我们不得不…

Django的数据库模型的CharField字段的max_length参数与中文字符数的关系探索(参数max_length的单位是字符个数还是字节数?)

01-清理干净之前的数据库迁移信息 02-根据setting.py中的信息删除掉之前建立的数据库 03-删除之后重新创建数据库 04-models.py中创建数据库模型 from django.db import modelsclass User(models.Model):username models.CharField(max_length4)email models.EmailField(uni…

RabbitMQ安装和快速入门

文章目录 1. RabbitMQ2. 安装RabbitMQ2.1 创建shell文件2.2 编写shell文件2.3 检查rabbitmq状态2.4 设置开机自启动2.5 启动插件2.6 开放端口号2.7 创建用户2.8 登入管理页面 3. SpringBoot中集成RabbitMQ3.1 依赖安装3.2 SpringBoot配置3.3 RabbitMQ的配置类3.4 定义消费者和生…

【Cadence】sprobe的使用

实验目的&#xff1a;通过sprobe测试电路中某个节点的阻抗 这里通过sprobe测试输入阻抗&#xff0c;可以通过port来验证 设置如下&#xff1a; 说明&#xff1a;Z1代表sprobe往left看&#xff0c;Z2代表sprobe往right看 结果如下&#xff1a; 可以看到ZM1I0.Z2 顺便给出了I…

谷歌浏览器打不开设置

场景&#xff1a;谷歌浏览器页面空白&#xff0c;并且点击设置没有反应 忘记我是在哪找的解决方案了&#xff0c;先留个记号在这&#xff0c;方便下次查阅

0x53 区间DP

0x53 区间DP 到目前为止&#xff0c;我们介绍的线性DP一般从初态开始&#xff0c;沿着阶段的扩张向某个方向递推&#xff0c;直至计算出目标状态。区间DP也属于线性DP中的一种&#xff0c;它以“区间长度”作为DP的“阶段”&#xff0c;使用两个坐标&#xff08;区间的左右端点…

MongoDB查找命令find,让数据返回称心如意

业务系统接入数据库后&#xff0c;每天都有大量的数据写入数据库。面对逐日增加的数据&#xff0c;开发人员或数据分析人员&#xff0c;该如何读取数据&#xff0c;怎样设置条件&#xff0c;从数据库中查询数据&#xff1f; 本文基于mongodb的官方文档&#xff0c;整理出find命…

计算机组成原理-程序查询方式(流程图 演示过程 例题 定时查询 独占查询)

文章目录 总览IO方式简介程序查询方式程序查询方式流程图程序查询方式-例题小结 总览 IO方式简介 每次输一个字&#xff0c;就认为状态完成&#xff0c;CPU就会取走数据寄存器的内容 程序查询方式 此时模拟打印三个字符 假设此时三个字符在主存&#xff0c;CPU先从主存读一…

避免重复扣款:分布式支付系统的幂等性原理与实践

这是《百图解码支付系统设计与实现》专栏系列文章中的第&#xff08;6&#xff09;篇。 本文主要讲清楚什么是幂等性原理&#xff0c;在支付系统中的重要应用&#xff0c;业务幂等、全部幂等这些不同的幂等方案选型带来的收益和复杂度权衡&#xff0c;幂等击穿场景及可能的严重…

期末查分系统(c,链表实现)

主要功能&#xff1a; 分为三个身份: 学生:可以通过学号查询个人分数 老师&#xff1a;可以看所有学生成绩&#xff0c;单科排名&#xff08;正序&#xff0c;倒序&#xff09;&#xff0c;统计绩点&#xff0c;查看绩点排名前百分之n的学生 管理员端&#xff1a;可以创建链…

揭秘区块链的奥秘:链上智能如何诊断加密生态系统的健康状况

作者&#xff1a;shellyfootprint.network 数据源&#xff1a;Wallet Profile 在加密市场中&#xff0c;波动是家常便饭。就拿 2022 年来说&#xff0c;像 Terra、Celsius 和 FTX 这样的主要项目相继崩盘&#xff0c;搞得市场一片狼藉。这些情况往往让人措手不及&#xff0c;直…

openGauss学习笔记-192 openGauss 数据库运维-常见故障定位案例-XFS文件系统问题

文章目录 openGauss学习笔记-192 openGauss 数据库运维-常见故障定位案例-XFS文件系统问题192.1 在XFS文件系统中&#xff0c;使用du命令查询数据文件大小大于文件实际大小192.1.1 问题现象192.1.2 原因分析192.1.3 处理办法 192.2 在XFS文件系统中&#xff0c;出现文件损坏192…

工业智能网关如何保障数据通信安全

工业智能网关是组成工业物联网的重要设备&#xff0c;不仅可以起到数据交换、通信、边缘计算的功能&#xff0c;还可以发挥数据安全保障功能&#xff0c;保障工业物联网稳定、可持续。本篇就为大家简单介绍一下工业智能网关增强和确保数据通信安全的几种措施&#xff1a; 1、软…

nuxt pm2配置及使用

pm2简介 pm2是一个进程管理工具,可以用它来管理node进程&#xff0c;并查看node进程的状态&#xff0c;当然也支持性能监控&#xff0c;进程守护&#xff0c;负载均衡等功能&#xff0c;在前端和nodejs的世界中用的很多 pm2安装 安装pm2: $ npm install -g pm2查看pm2的安装…

232转Profinet实现协议互转的配置步骤

通常说的RS232是一种串口通信&#xff0c;通过发送和接收的电压变化来传递信息&#xff0c;是点对点通信&#xff0c;通信双方直接连接&#xff0c;通信速率较低。Profinet是一种以太网协议通信&#xff0c;具有传输速度快&#xff0c;支持多个设备实时应用&#xff0c;而且有更…

链表--141.环形链表/easy C级理解

141.环形链表 1、题目2、题目分析3、解题步骤4、复杂度最优解代码示例5、抽象与扩展 1、题目 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链…

如何保护linux服务器远程使用的安全

服务器安全是一个非常敏感的问题&#xff0c;因服务器远程入侵导致数据丢失的安全问题频频出现&#xff0c;一旦服务器入侵就会对个人和企业造成巨大的损失。因此&#xff0c;在日常使用服务器的时候&#xff0c;我们需要采取一些安全措施来保障服务器的安全性。 目前服务器系…