当前位置: 首页 > news >正文

ASP.NET Core 分层项目中EFCore的使用

文章目录

  • 前言
  • 一、核心
  • 二、项目分层结构
    • 1)安装 NuGet 包
      • Web 项目
      • InfrastructureLibrary项目
    • 2)领域模型和仓储接口 (Domain 层)
    • 3)基础设施层实现 (Infrastructure 层)
    • 4)应用层服务 (Application 层)
    • 5)Web API 配置
    • 6)控制器 (Web 层)
    • 7)数据库迁移
  • 三、关键点说明
    • 分层依赖:
    • 依赖注入:
    • 异步操作:
    • 领域驱动设计:
  • 总结


前言

ASP.NET Core Web API 结合 Entity Framework Core (EF Core) 的分层项目架构是一种常见的开发模式,旨在通过职责分离提高代码的可维护性、可测试性和扩展性。

一、核心

分层架构将应用按功能划分为多个逻辑层,各层职责明确,通过接口或 DTO(Data Transfer Object)通信。

二、项目分层结构

  1. Presentation层 (Web API) - 处理 HTTP 请求/响应

  2. Application层 - 业务逻辑和用例实现

  3. Domain层 - 实体模型和仓储接口

  4. Infrastructure层 - EFCore 实现和数据库配置

    MyAspNetCoreWebApplication.sln
    ├─ MyAspNetCoreWebApplication.MyWebApplication(ASP.NET Core Web API)
    ├─ MyAspNetCoreWebApplication.ApplicationLibrary(Class Library)
    ├─ MyAspNetCoreWebApplication.DomainLibrary(Class Library)
    └─ MyAspNetCoreWebApplication.InfrastructureLibrary(Class Library)
    

1)安装 NuGet 包

Web 项目

Microsoft.EntityFrameworkCore.SqlServer

InfrastructureLibrary项目

Install-Package Microsoft.EntityFrameworkCore
Install-Package Microsoft.EntityFrameworkCore.Design
Install-Package Microsoft.EntityFrameworkCore.Tools
Microsoft.Extensions.Configuration
Microsoft.Extensions.Configuration.EnvironmentVariables

2)领域模型和仓储接口 (Domain 层)

  1. 实体(Entity)
    目录结构:DomainLibrary-Entity
    • Book.cs
    public class Book
    {public long Id { get; set; }public string Title { get; set; }public double Price { get; set; }public string AuthorId { get; set; }public string AuthorName { get; set; }
    }
    
    • Product.cs
    public class Product
    {public long Id { get; set; }public string Name { get; set; }public string Description { get; set; }public double Price { get; set; }
    }
    
  2. 仓储接口(RepositoryInterface)
    目录结构:DomainLibrary-Repository
    • IBookRepository.cs
    public interface IBookRepository
    {Task<IEnumerable<Book>> GetAllAsync();Task<Book> GetByIdAsync(long id);Task AddAsync(Book book);Task DeleteAsync(long id);Task UpdateAsync(Book book);
    }
    
    • IProjectRepository.cs
     public interface IProjectRepository{Task<IEnumerable<Product>>  GetAllAsync();Task<Product> GetByIdAsync(long id);Task AddAsync(Product project);Task DeleteAsync(long id);Task UpdateAsync(Product project);}
    

3)基础设施层实现 (Infrastructure 层)

  1. 数据库上下文类
    目录结构:InfrastructureLibrary-Data

    • MyDbContext.cs
      public class MyDbContext : DbContext
      {public MyDbContext(DbContextOptions<MyDbContext> options) : base(options){}public DbSet<Product> Projects { get; set; }public DbSet<Book> Books { get; set; }protected override void OnModelCreating(ModelBuilder modelBuilder){base.OnModelCreating(modelBuilder);modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly);}}
      
    • MyDbContextDesignFactory.cs
      internal class MyDbContextDesignFactory : IDesignTimeDbContextFactory<MyDbContext>
      {public MyDbContext CreateDbContext(string[] args){// 手动构建配置(读取环境变量)var configuration = new ConfigurationBuilder().AddEnvironmentVariables() // 添加环境变量作为配置源.Build();string connStr = configuration.GetSection("ConnStr").Value;if (connStr == null){throw new Exception("连接字符串为空");}DbContextOptionsBuilder<MyDbContext> opt = new DbContextOptionsBuilder<MyDbContext>();opt.UseSqlServer(connStr);return new MyDbContext(opt.Options);}
      }
      
  2. 配置类
    目录结构:InfrastructureLibrary-Config

    • BookConfig.cs
      public class BookConfig : IEntityTypeConfiguration<Book>
      {public void Configure(EntityTypeBuilder<Book> builder){builder.ToTable("T_Books");}
      }
      
    • ProductConfig.cs
       public class ProductConfig : IEntityTypeConfiguration<Product>{public void Configure(EntityTypeBuilder<Product> builder){builder.ToTable("T_Products");builder.Property(p => p.Name).HasMaxLength(100).IsRequired();builder.Property(p => p.Price).HasColumnType("decimal(18,2)");}}
      
  3. 实现类Repositories
    目录结构:InfrastructureLibrary-Repositories

    • BookRepository.cs
      public class BookRepository
      {private readonly MyDbContext _dbContext;public BookRepository(MyDbContext context){_dbContext = context;}public async Task<IEnumerable<Book>> GetAllAsync()=> await _dbContext.Books.ToListAsync();public async Task<Book> GetByIdAsync(long id)=> await _dbContext.Books.FindAsync(id);public async Task AddAsync(Book book){if (book != null){await _dbContext.Books.AddAsync(book);await _dbContext.SaveChangesAsync();}}public async Task DeleteAsync(long id){Book p = await GetByIdAsync(id);if (p != null){_dbContext.Books.Remove(p);await _dbContext.SaveChangesAsync();}}public async Task UpdateAsync(Book book){if (book != null){_dbContext.Books.Update(book);await _dbContext.SaveChangesAsync();}}
      }
      
    • ProductRepository.cs
      public class ProductRepository : IProjectRepository
      {private readonly MyDbContext _dbContext;public ProductRepository(MyDbContext dbContext){_dbContext = dbContext;}public async Task<IEnumerable<Product>> GetAllAsync()=> await _dbContext.Projects.ToListAsync();public async Task<Product> GetByIdAsync(long id)=> await _dbContext.Projects.FindAsync(id);public async Task AddAsync(Product project){if (project!=null){await _dbContext.Projects.AddAsync(project);await _dbContext.SaveChangesAsync();}            }public async Task DeleteAsync(long id){Product p=await GetByIdAsync(id);if (p != null){_dbContext.Projects.Remove(p);await _dbContext.SaveChangesAsync();}}public async Task UpdateAsync(Product project){if (project != null){_dbContext.Projects.Update(project);await _dbContext.SaveChangesAsync();}}
      }
      

4)应用层服务 (Application 层)

  1. 服务类
    目录结构:ApplicationLibrary-Services
    • BookService.cs
      public class BookService
      {private readonly IBookRepository bookRepository;public BookService(IBookRepository bookRepository){this.bookRepository = bookRepository;}public async Task<IEnumerable<Book>> GetAllBookAsync(){return await bookRepository.GetAllAsync();}public async Task<Book> GetBookById(long id){return await bookRepository.GetByIdAsync(id);}public async Task AddBook(Book book)=> await bookRepository.AddAsync(book);public async Task UpdateBook(Book book)=> await bookRepository.UpdateAsync(book);public async Task DeleteBook(long id)=> await bookRepository.DeleteAsync(id);
      }
      
    • ProductService.cs
      public class ProductService
      {private readonly IProjectRepository _repository;public ProductService(IProjectRepository repository){_repository = repository;}public async Task<IEnumerable<Product>> GetAllProjectAsync(){return await _repository.GetAllAsync();}public async Task<Product> GetProductById(long id){return await _repository.GetByIdAsync(id);}public async Task AddProduct(Product product)=>await _repository.AddAsync(product);public async Task UpdateProject(Product product)=> await _repository.UpdateAsync(product);public async Task DeleteProduct(long id)=> await _repository.DeleteAsync(id);}
      

5)Web API 配置

  1. Program.cs 配置

    • Program.cs
      using DomainLibrary.Repository;
      using InfrastructureLibrary.Repositories;
      using Microsoft.EntityFrameworkCore;
      using ApplicationLibrary.Services;
      using InfrastructureLibrary.Data;var builder = WebApplication.CreateBuilder(args);// Add services to the container.
      //配置数据库
      builder.Services.AddDbContext<MyDbContext>(opt => {string connStr = builder.Configuration.GetConnectionString("DefaultConnection");//GetSection("ConnStr").Value;opt.UseSqlServer(connStr);
      });// 注册仓储
      builder.Services.AddScoped<IProjectRepository, ProductRepository>();//注册服务
      builder.Services.AddScoped<ProductService>();builder.Services.AddControllers();builder.Services.AddEndpointsApiExplorer();
      builder.Services.AddSwaggerGen();var app = builder.Build();// 自动迁移数据库(可选)
      using (var scope = app.Services.CreateScope())
      {var db = scope.ServiceProvider.GetRequiredService<MyDbContext>();db.Database.Migrate();
      }// Configure the HTTP request pipeline.
      if (app.Environment.IsDevelopment())
      {app.UseSwagger();app.UseSwaggerUI();
      }app.UseHttpsRedirection();app.UseAuthorization();app.MapControllers();app.Run();
      
  2. appsettings.json配置

    • appsettings.json
      {"Logging": {"LogLevel": {"Default": "Information","Microsoft.AspNetCore": "Warning"}},"AllowedHosts": "*","ConnectionStrings": {"DefaultConnection": "Server=XXX;Database=XXX;User Id=sa;Password=XXX;TrustServerCertificate=True;Trusted_Connection=True;MultipleActiveResultSets=True"}
      }
      

6)控制器 (Web 层)

  1. 控制器示例
    • TestController.cs
       [Route("api/[controller]/[action]")][ApiController]public class TestController : ControllerBase{private readonly MyDbContext _db;private readonly ProductService _productService;public TestController(MyDbContext db, ProductService productService){_db = db;_productService = productService;}[HttpGet]public ActionResult<string> Get(){var count= _db.Books.Count();return $"count={count}";}[HttpGet]public async Task<IActionResult> GetAllProductsAsync(){var res=await _productService.GetAllProjectAsync();return Ok(res);}}
      

7)数据库迁移

  1. 打开包管理器控制台
  2. 设置默认项目为 InfrastructureLibrary
  3. 执行命令:
    Add-Migration Init
    Update-Database
    

三、关键点说明

分层依赖:

  1. Web 层引用 ApplicationInfrastructureDomain
  2. Application 层引用 DomainInfrastructure
  3. Infrastructure 层引用 Domain

依赖注入:

  1. 通过构造函数注入仓储和服务
  2. 使用 AddScoped 注册生命周期服务

异步操作:

  1. 所有数据库操作使用 async/await
  2. 使用 ToListAsync()FindAsync() 等异步方法

领域驱动设计:

  1. 仓储模式隔离数据访问细节
  2. 领域模型保持纯净无基础设施依赖

总结

分层架构在 ASP.NET Core Web API + EF Core 项目中通过职责分离提升了代码质量,但需要权衡设计复杂度和实际需求。通过合理分层、依赖注入和接口抽象,可以构建高可维护、可测试的应用程序,同时避免过度设计。最终,架构选择应服务于业务需求,而非盲目追求分层形式。

http://www.xdnf.cn/news/55675.html

相关文章:

  • Linux下 REEF3D及DIVEMesh 源码编译安装及使用
  • CGAL 计算直线之间的距离(3D)
  • 红队专题-漏洞挖掘-代码审计-反序列化
  • C++初阶的应用-日期管理系统的设计与实现
  • SSM--事务
  • 【TeamFlow】4 团队管理系统
  • 卡洛诗以“中式西餐”为锚点
  • C++运算符重载详解
  • puzzle(0531)脑力航迹
  • 【计量地理学】实验八 土壤重金属Zn污染范围的界定与不确定性分析
  • SpringCloud
  • 火箭姿态控制系统
  • RV1126网络环境TFTPNFS搭建(四)
  • C++学习:六个月从基础到就业——内存管理:内存泄漏与避免
  • 一文读懂Python之numpy模块(34)
  • 02_解决Class com.sun.tools.javac.tree.JCTree
  • STM32基础教程——HEX数据包接收
  • 域名解析,配置Linux系统的固定IP地址
  • 用python + PIL 实现图片格式转换工具
  • 5 提示词工程指南-计划与行动
  • 重读《人件》Peopleware -(8)Ⅱ办公环境Ⅰ家具警察
  • 【Python语言基础】23、文件处理
  • HTML表单与数据验证设计
  • [Spring]SSM整合
  • Nginx静态资源跳转添加权限验证
  • 不确定与非单调推理的模糊推理
  • c语言修炼秘籍 - - 禁(进)忌(阶)秘(技)术(巧)【第六式】文件操作
  • System.out 详解
  • 东京 ⇄ 京都游记⛩️
  • Linux 420 find stat touch tree scp crontab