下面是一个完整的 .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
csharp
public class Student
{
public int Id { get; set; }
public int ClassId { get; set; }
public string Name { get; set; }
}
Models/Course.cs
csharp
public class Course
{
public int Id { get; set; }
public string Name { get; set; }
}
Models/Grade.cs
csharp
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
csharp
public class Class
{
public int Id { get; set; }
public string Name { get; set; }
}
数据传输对象
为了优化网络传输,我们通常不会直接返回实体模型,而是使用DTO。
DTOs/StudentGradeDTO.cs
csharp
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
csharp
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
csharp
using Dapper;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using Oracle.ManagedDataAccess.Client;
public class StudentRepository
{
private readonly string _connectionString;
public StudentRepository(string connectionString)
{
_connectionString = connectionString;
}
public List<Student> GetAllStudents()
{
using (var connection = new OracleConnection(_connectionString))
{
return connection.Query<Student>("SELECT * FROM Students").ToList();
}
}
public List<Student> GetPagedStudents(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 connection.Query<Student>(sql, new { offset, pageSize }).ToList();
}
}
public Student GetStudentById(int id)
{
using (var connection = new OracleConnection(_connectionString))
{
return connection.QueryFirstOrDefault<Student>("SELECT * FROM Students WHERE Id = :id", new { id });
}
}
public void AddStudent(Student student)
{
using (var connection = new OracleConnection(_connectionString))
{
connection.Execute("INSERT INTO Students (ClassId, Name) VALUES (:classId, :name)", new { student.ClassId, student.Name });
}
}
public void UpdateStudent(Student student)
{
using (var connection = new OracleConnection(_connectionString))
{
connection.Execute("UPDATE Students SET ClassId = :classId, Name = :name WHERE Id = :id", new { student.ClassId, student.Name, student.Id });
}
}
public void DeleteStudent(int id)
{
using (var connection = new OracleConnection(_connectionString))
{
connection.Execute("DELETE FROM Students WHERE Id = :id", new { id });
}
}
public List<StudentGradeDTO> GetStudentGradesByClassId(int classId)
{
using (var connection = new OracleConnection(_connectionString))
{
var sql = @"SELECT s.Id AS StudentId, s.Name AS StudentName, c.Name AS CourseName, g.Score
FROM Students s
JOIN Grades g ON s.Id = g.StudentId
JOIN Courses c ON g.CourseId = c.Id
WHERE s.ClassId = :classId";
return connection.Query<StudentGradeDTO>(sql, new { classId }).ToList();
}
}
}
服务层
服务层处理业务逻辑,调用仓库层的方法来完成具体的功能,并集成缓存逻辑。
Services/StudentService.cs
csharp
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 Task.FromResult(_repository.GetAllStudents());
}
public async Task<List<Student>> GetPagedStudentsAsync(int page, int pageSize)
{
return await _pagedStudentCache.GetOrAddAsync((page, pageSize), async key => await Task.FromResult(_repository.GetPagedStudents(key.Page, key.PageSize)));
}
public async Task<Student> GetStudentByIdAsync(int id)
{
return await _studentCache.GetOrAddAsync(id, async key => await Task.FromResult(_repository.GetStudentById(key)));
}
public void AddStudent(Student student)
{
_repository.AddStudent(student);
}
public void UpdateStudent(Student student)
{
_repository.UpdateStudent(student);
}
public void DeleteStudent(int id)
{
_repository.DeleteStudent(id);
}
public async Task<List<StudentGradeDTO>> GetStudentGradesByClassIdAsync(int classId)
{
return await _studentGradesCache.GetOrAddAsync(classId, async key => await Task.FromResult(_repository.GetStudentGradesByClassId(key)));
}
}
控制层
控制层接收客户端请求,并调用服务层提供的方法来处理请求。
Controllers/StudentController.cs
csharp
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)
{
_service.AddStudent(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();
}
_service.UpdateStudent(student);
return NoContent();
}
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteStudentAsync(int id)
{
_service.DeleteStudent(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
csharp
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
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
csharp
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 数据库,并实现了学生表、课程表、成绩表和班级表的基本增删改查功能,以及查询某个班级学生成绩的功能。查询功能使用了自定义缓存来优化性能。希望这些代码对你有所帮助!