下面是一个完整的 .NET Core 后端项目示例,使用 Dapper 作为轻量级 ORM 访问 Oracle 数据库,并实现高性能架构。我们将实现学生表、课程表、成绩表和班级表的基本增删改查功能,以及查询某个班级学生成绩的功能,并使用自定义缓存来优化查询性能。所有数据访问操作都将使用异步方式。
项目结构
MyApp/
│── Controllers/ # 控制器层,处理HTTP请求
│ └── StudentController.cs
│── Models/ # 模型层,定义实体类
│ ├── Student.cs
│ ├── Course.cs
│ ├── Grade.cs
│ └── Class.cs
│── DTOs/ # 数据传输对象,用于API响应
│ └── StudentGradeDTO.cs
│── Services/ # 服务层,业务逻辑处理
│ └── StudentService.cs
│── Repositories/ # 仓库层,数据访问
│ └── StudentRepository.cs
│── Cache/ # 缓存层
│ └── InMemoryCache.cs
│── Startup.cs # 应用启动配置
│── appsettings.json # 应用配置文件
└── Program.cs # 应用入口
实体模型
首先定义实体模型,这些模型代表数据库中的表。
Models/Student.cs
public class Student
{public int Id { get; set; }public int ClassId { get; set; }public string Name { get; set; }
}
Models/Course.cs
public class Course
{public int Id { get; set; }public string Name { get; set; }
}
Models/Grade.cs
public class Grade
{public int Id { get; set; }public int StudentId { get; set; }public int CourseId { get; set; }public decimal Score { get; set; }
}
Models/Class.cs
public class Class
{public int Id { get; set; }public string Name { get; set; }
}
数据传输对象
为了优化网络传输,我们通常不会直接返回实体模型,而是使用DTO。
DTOs/StudentGradeDTO.cs
public class StudentGradeDTO
{public int StudentId { get; set; }public string StudentName { get; set; }public string CourseName { get; set; }public decimal Score { get; set; }
}
缓存层
我们使用一个简单的字典来实现内存缓存。
Cache/InMemoryCache.cs
using System;
using System.Collections.Generic;
using System.Threading.Tasks;public class InMemoryCache<TKey, TValue>
{private readonly Dictionary<TKey, CacheEntry<TValue>> _cache = new Dictionary<TKey, CacheEntry<TValue>>();public async Task<TValue> GetOrAddAsync(TKey key, Func<TKey, Task<TValue>> valueFactory, TimeSpan? expiration = null){if (_cache.TryGetValue(key, out var cacheEntry)){if (cacheEntry.Expiration > DateTime.UtcNow){return cacheEntry.Value;}else{_cache.Remove(key);}}var value = await valueFactory(key);_cache[key] = new CacheEntry<TValue> { Value = value, Expiration = DateTime.UtcNow + (expiration ?? TimeSpan.FromMinutes(5)) };return value;}private class CacheEntry<T>{public T Value { get; set; }public DateTime Expiration { get; set; }}
}
仓库层
仓库层负责与数据库交互,执行具体的SQL命令。
Repositories/StudentRepository.cs
using Dapper;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using Oracle.ManagedDataAccess.Client;public class StudentRepository
{private readonly string _connectionString;public StudentRepository(string connectionString){_connectionString = connectionString;}public async Task<List<Student>> GetAllStudentsAsync(){using (var connection = new OracleConnection(_connectionString)){return (await connection.QueryAsync<Student>("SELECT * FROM Students")).ToList();}}public async Task<List<Student>> GetPagedStudentsAsync(int page, int pageSize){using (var connection = new OracleConnection(_connectionString)){int offset = (page - 1) * pageSize;var sql = $"SELECT * FROM Students ORDER BY Id OFFSET :offset ROWS FETCH NEXT :pageSize ROWS ONLY";return (await connection.QueryAsync<Student>(sql, new { offset, pageSize })).ToList();}}public async Task<Student> GetStudentByIdAsync(int id){using (var connection = new OracleConnection(_connectionString)){return await connection.QueryFirstOrDefaultAsync<Student>("SELECT * FROM Students WHERE Id = :id", new { id });}}public async Task AddStudentAsync(Student student){using (var connection = new OracleConnection(_connectionString)){await connection.ExecuteAsync("INSERT INTO Students (ClassId, Name) VALUES (:classId, :name)", new { student.ClassId, student.Name });}}public async Task UpdateStudentAsync(Student student){using (var connection = new OracleConnection(_connectionString)){await connection.ExecuteAsync("UPDATE Students SET ClassId = :classId, Name = :name WHERE Id = :id", new { student.ClassId, student.Name, student.Id });}}public async Task DeleteStudentAsync(int id){using (var connection = new OracleConnection(_connectionString)){await connection.ExecuteAsync("DELETE FROM Students WHERE Id = :id", new { id });}}public async Task<List<StudentGradeDTO>> GetStudentGradesByClassIdAsync(int classId){using (var connection = new OracleConnection(_connectionString)){var sql = @"SELECT s.Id AS StudentId, s.Name AS StudentName, c.Name AS CourseName, g.ScoreFROM Students sJOIN Grades g ON s.Id = g.StudentIdJOIN Courses c ON g.CourseId = c.IdWHERE s.ClassId = :classId";return (await connection.QueryAsync<StudentGradeDTO>(sql, new { classId })).ToList();}}
}
服务层
服务层处理业务逻辑,调用仓库层的方法来完成具体的功能,并集成缓存逻辑。
Services/StudentService.cs
using System.Collections.Generic;
using System.Threading.Tasks;public class StudentService
{private readonly StudentRepository _repository;private readonly InMemoryCache<int, Student> _studentCache;private readonly InMemoryCache<(int Page, int PageSize), List<Student>> _pagedStudentCache;private readonly InMemoryCache<int, List<StudentGradeDTO>> _studentGradesCache;public StudentService(StudentRepository repository){_repository = repository;_studentCache = new InMemoryCache<int, Student>();_pagedStudentCache = new InMemoryCache<(int Page, int PageSize), List<Student>>();_studentGradesCache = new InMemoryCache<int, List<StudentGradeDTO>>();}public async Task<List<Student>> GetAllStudentsAsync(){return await _repository.GetAllStudentsAsync();}public async Task<List<Student>> GetPagedStudentsAsync(int page, int pageSize){return await _pagedStudentCache.GetOrAddAsync((page, pageSize), async key => await _repository.GetPagedStudentsAsync(key.Page, key.PageSize));}public async Task<Student> GetStudentByIdAsync(int id){return await _studentCache.GetOrAddAsync(id, async key => await _repository.GetStudentByIdAsync(key));}public async Task AddStudentAsync(Student student){await _repository.AddStudentAsync(student);}public async Task UpdateStudentAsync(Student student){await _repository.UpdateStudentAsync(student);}public async Task DeleteStudentAsync(int id){await _repository.DeleteStudentAsync(id);}public async Task<List<StudentGradeDTO>> GetStudentGradesByClassIdAsync(int classId){return await _studentGradesCache.GetOrAddAsync(classId, async key => await _repository.GetStudentGradesByClassIdAsync(key));}
}
控制层
控制层接收客户端请求,并调用服务层提供的方法来处理请求。
Controllers/StudentController.cs
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Threading.Tasks;[ApiController]
[Route("api/[controller]")]
public class StudentController : ControllerBase
{private readonly StudentService _service;public StudentController(StudentService service){_service = service;}[HttpGet]public async Task<ActionResult<List<Student>>> GetAllStudentsAsync(){return Ok(await _service.GetAllStudentsAsync());}[HttpGet("paged")]public async Task<ActionResult<List<Student>>> GetPagedStudentsAsync(int page = 1, int pageSize = 10){return Ok(await _service.GetPagedStudentsAsync(page, pageSize));}[HttpGet("{id}")]public async Task<ActionResult<Student>> GetStudentByIdAsync(int id){var student = await _service.GetStudentByIdAsync(id);if (student == null){return NotFound();}return Ok(student);}[HttpPost]public async Task<ActionResult<Student>> AddStudentAsync([FromBody] Student student){await _service.AddStudentAsync(student);return CreatedAtAction(nameof(GetStudentByIdAsync), new { id = student.Id }, student);}[HttpPut("{id}")]public async Task<IActionResult> UpdateStudentAsync(int id, [FromBody] Student student){if (id != student.Id){return BadRequest();}await _service.UpdateStudentAsync(student);return NoContent();}[HttpDelete("{id}")]public async Task<IActionResult> DeleteStudentAsync(int id){await _service.DeleteStudentAsync(id);return NoContent();}[HttpGet("class/{classId}/grades")]public async Task<ActionResult<List<StudentGradeDTO>>> GetStudentGradesByClassIdAsync(int classId){return Ok(await _service.GetStudentGradesByClassIdAsync(classId));}
}
配置依赖注入
在 Startup.cs
中配置依赖注入,以便可以在控制器和服务之间共享仓库实例。
Startup.cs
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using MyApp.Repositories;
using MyApp.Services;public class Startup
{public Startup(IConfiguration configuration){Configuration = configuration;}public IConfiguration Configuration { get; }public void ConfigureServices(IServiceCollection services){services.AddControllers();services.AddScoped<StudentRepository>(provider => new StudentRepository(Configuration.GetConnectionString("DefaultConnection")));services.AddScoped<StudentService>();}public void Configure(IApplicationBuilder app, IWebHostEnvironment env){if (env.IsDevelopment()){app.UseDeveloperExceptionPage();}app.UseRouting();app.UseAuthorization();app.UseEndpoints(endpoints =>{endpoints.MapControllers();});}
}
配置文件
在 appsettings.json
中配置数据库连接字符串。
appsettings.json
{"ConnectionStrings": {"DefaultConnection": "User Id=your_username;Password=your_password;Data Source=your_data_source;"},"Logging": {"LogLevel": {"Default": "Information","Microsoft": "Warning","Microsoft.Hosting.Lifetime": "Information"}},"AllowedHosts": "*"
}
应用入口
Program.cs
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;public class Program
{public static void Main(string[] args){CreateHostBuilder(args).Build().Run();}public static IHostBuilder CreateHostBuilder(string[] args) =>Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder =>{webBuilder.UseStartup<Startup>();});
}
总结
通过上述代码,我们实现了一个高性能的 .NET Core 后端项目,使用 Dapper 访问 Oracle 数据库,并实现了学生表、课程表、成绩表和班级表的基本增删改查功能,以及查询某个班级学生成绩的功能。查询功能使用了自定义缓存来优化性能,所有数据访问操作都使用了异步方式。希望这些代码对你有所帮助!