Bootstrap

AI生成的一个.netcore 经典后端架构

下面是一个完整的 .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 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

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

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

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 数据库,并实现了学生表、课程表、成绩表和班级表的基本增删改查功能,以及查询某个班级学生成绩的功能。查询功能使用了自定义缓存来优化性能。希望这些代码对你有所帮助!

;