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

发布于:2025-04-22 ⋅ 阅读:(12) ⋅ 点赞:(0)


前言

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


网站公告

今日签到

点亮在社区的每一天
去签到