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

news2024/9/20 1:11:19

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. “小上下文” 策略的好处:
    • 一个上下文实例初始化的时候,实体类的配置等过程将非常快,其不会成为性能瓶颈
    • 如果启用了数据库连接池,数据库连接的创建也不会成为性能瓶颈。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java常用应用程序编程接口(API)——String概述及使用案例

前言&#xff1a; 开始学到api的String&#xff0c;整理下心得。打好基础&#xff0c;daydayup! API&#xff1a; API是什么&#xff1f; API&#xff08;Application Programming Interface&#xff09;又名应用程序编程接口。是别人编好的程序的合集。 为什么要使用API&…

计算机基础面试题 |17.精选计算机基础面试题

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

详解Java中的serialVersionUID概念以及作用(附上Demo)

目录 前言1. 概念2. Demo 前言 原本实现Serializable接口的时候一直都没有serialVersionUID属性&#xff0c;直到看到涉及MybatisPlus新项目中都有该属性&#xff0c;于是做了一期学习了解&#xff0c;最后发现该属性类似深度学习训练中的种子seed&#xff0c;类似版本控制&am…

RuntimeError: CUDA error: invalid device ordinal解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

Vue.js设计与实现阅读2

Vue.js设计与实现阅读-2 1、前言2、框架设计的核心要素2、1 提升用户体验2、2 控制代码体积2、3 Tree-Shaking2、4 特性开关2、5 错误处理 1、前言 上一篇我们了解到了 命令式和声明式的区别&#xff0c;前者关注过程&#xff0c;后者关注结果了解了虚拟dom存在的意义&#x…

[C#]winform部署yolov5-onnx模型

【官方框架地址】 https://github.com/ultralytics/yolov5 【算法介绍】 Yolov5&#xff0c;全称为You Only Look Once version 5&#xff0c;是计算机视觉领域目标检测算法的一个里程碑式模型。该模型由ultralytics团队开发&#xff0c;并因其简洁高效的特点而备受关注。Yol…

异常处理:全面覆盖与精细化管理的平衡

异常处理&#xff1a;全面覆盖与精细化管理的平衡 在软件开发中&#xff0c;异常处理是保证系统稳定性和用户体验的重要环节。对于是否应当全面覆盖所有异常并设立兜底机制&#xff0c;业界存在着两种主流思路&#xff1a;全面覆盖原则和精细化处理。如何在这两者间取得平衡&a…

嵌入式Qt-动手编写并运行自己的第1个ARM-Qt程序

介绍了如何搭建在Linux开发板中搭建Qt的运行环境&#xff0c;并测试了Qt自带的例程。 本篇&#xff0c;来介绍如何自己编写一个Qt程序&#xff0c;并将编译结果放到Linux开发板中运行。 1 Windows上编写Qt程序 因为Qt是支持跨平台的&#xff0c;所以我们可以先在Windows平台…

一天一个设计模式---单例模式

概念 单例模式是一种创建型设计模式&#xff0c;其主要目的是确保一个类只有一个实例&#xff0c;并提供一个全局访问点。这意味着在应用程序中的任何地方&#xff0c;只能有一个实例存在&#xff0c;而不会创建多个相同类型的实例。 具体内容 单例模式通常包括以下几个要素…

深度学习:图神经网络——在推荐系统中的应用

PinSage是工业界应用图神经网络完成推荐任务的第一个成功案例&#xff0c;其从用户数据中构造图&#xff08;graph&#xff09;的方法和应对大规模图而采取的实现技巧都值得我们学习。PinSage被应用在图片推荐类Pinterest上。在Pinterest中&#xff0c;每个用户可以创建并命名图…

工程管理系统功能设计与实践:实现高效、透明的工程管理

在现代化的工程项目管理中&#xff0c;一套功能全面、操作便捷的系统至关重要。本文将介绍一个基于Spring Cloud和Spring Boot技术的Java版工程项目管理系统&#xff0c;结合Vue和ElementUI实现前后端分离。该系统涵盖了项目管理、合同管理、预警管理、竣工管理、质量管理等多个…

深入了解网络流量清洗--使用免费的雷池社区版进行防护

​ 随着网络攻击日益复杂&#xff0c;企业面临的网络安全挑战也在不断增加。在这个背景下&#xff0c;网络流量清洗成为了确保企业网络安全的关键技术。本文将探讨雷池社区版如何通过网络流量清洗技术&#xff0c;帮助企业有效应对网络威胁。 ![] 网络流量清洗的重要性&#x…

Wpf 使用 Prism 实战开发Day08

备忘录页面设计 1.效果图 一.布局设计跟第7章节一样&#xff0c;只是内容方面发生变化&#xff0c;其他样式都一样。直接把代码粘出来了 MemoView.xaml 页面代码 <UserControl x:Class"MyToDo.Views.MemoView"xmlns"http://schemas.microsoft.com/winfx/2…

jQuery页面整屏滚动

效果展示 jQuery页面整屏滚动 Html代码块 <div id"fullpage" class"fullpage-index"><!-- index01 --><div class"indexitem index01 section" id"#page1"><img src"img/img01.jpg"/></div>…

设计模式——工厂方法模式(Factory Method Pattern)

简单工厂模式 概述 说工厂方法模式之前&#xff0c;先说下简单工厂模式&#xff0c;简单工厂模式并不属于GoF 23个经典设计模式&#xff0c;但通常将它作为学习其他工厂模式的基础&#xff0c;它的设计思想很简单&#xff0c;其基本流程如下&#xff1a;首先将需要创建的各种不…

NODE笔记 0

一些简单的node学习笔记记录&#xff0c;是Vue等前端框架的基础 入门学习备忘录 文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 node.js 内置网络服务器&#xff0c;是前端框架学习的基础&#xff1a; 概念&#xff1a;…

大模型机器人发展史:从VoxPoser、RT2到斯坦福Mobile ALOHA、Google机器人

前言 23年7月&#xff0c;我在朋友圈评估Google的RT2说道&#xff1a; “大模型正在革新一切领域啊&#xff0c;超帅&#xff0c;通过大模型不仅能理解“人话”&#xff0c;还能对“人话”进行推理&#xff0c;并转变为机器人能理解的指令&#xff0c;从而分阶段完成任务。回…

Web前端-jQuery

文章目录 jQuery1.1 jQuery 介绍1.1.1 JavaScript 库1.1.2 jQuery的概念1.1.3 jQuery的优点 1.2 jQuery 的基本使用1.2.1 jQuery 的下载1.2.2 jQuery快速入门1.2.3 jQuery入口函数1.2.4 jQuery中的顶级对象$1.2.5 jQuery 对象和 DOM 对象1.2.6. jQuery 对象和 DOM 对象转换 1.3…

二叉树OJ练习(二)

1. 二叉树的最近公共祖先 题目描述&#xff1a; ​ 题解: 1.p或者q其中一个等于root&#xff0c;那么root就是最进公共祖先 2.p和q分布在root的左右两侧&#xff0c;那么root就是最进公共祖先 3.p和q在root的同一侧&#xff0c;就是要遍历这棵树&#xff0c;遇到p或者q返回 ​…

数据结构—图(下)

文章目录 12.图(下)(4).生成树和最小生成树#1.什么是生成树和最小生成树&#xff1f;i.生成树ii.最小生成树 #2.Prim算法i.算法思想ii.看看例子iii.代码实现 #3.Kruskal算法i.算法思想ii.看看例子iii.代码实现 #4.次小生成树 (5).最短路径问题#1.加权有向图的最短路径问题#2.单…