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

news2024/11/29 10:30:32

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2249690.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Layui表格的分页下拉框新增“全部”选项

1、首先需要从后端接口获取表格的全部数据长度&#xff0c;这里以100为例。 2、根据请求到的数据进行表格的渲染。示例代码&#xff1a; let pageSize 5 let pageNo 1 let count 100 table.render({elem: XXX,done: function(res, curr, count){pageNo curr; // 将当前选…

CBK7运营安全

1 运营部门的角色 ​ prudent man、due care&#xff08;按要求执行&#xff09;VS due diligence&#xff08;承担管理者责任&#xff09; ​ 应尽关注&#xff1a;执行了负责任的动作降低了风险。 ​ 应尽职责&#xff1a;采取了所有必要的安全步骤以了解公司或个人的实际风…

AIGC引领金融大模型革命:未来已来

文章目录 金融大模型的应用场景1. **金融风险管理**2. **量化交易**3. **个性化投资建议**4. **金融欺诈检测和预防**5. **智能客户服务** 金融大模型开发面临的挑战应对策略《金融大模型开发基础与实践》亮点内容简介作者简介获取方式 在AIGC&#xff08;Artificial Intellige…

Linux操作系统2-进程控制3(进程替换,exec相关函数和系统调用)

上篇文章&#xff1a;Linux操作系统2-进程控制2(进程等待&#xff0c;waitpid系统调用&#xff0c;阻塞与非阻塞等待)-CSDN博客 本篇代码Gitee仓库&#xff1a;Linux操作系统-进程的程序替换学习 d0f7bb4 橘子真甜/linux学习 - Gitee.com 本篇重点&#xff1a;进程替换 目录 …

Java函数式编程+Lambda表达式

文章目录 函数式编程介绍纯函数Lambda表达式基础Lambda的引入传统方法1. 顶层类2. 内部类3. 匿名类 Lambda 函数式接口&#xff08;Functional Interface&#xff09;1. **函数式接口的定义**示例&#xff1a; 2. **函数式接口与Lambda表达式的关系**关联逻辑&#xff1a;示例&…

DI依赖注入详解

DI依赖注入 声明了一个成员变量&#xff08;对象&#xff09;之后&#xff0c;在该对象上面加上注解AutoWired注解&#xff0c;那么在程序运行时&#xff0c;该对象自动在IOC容器中寻找对应的bean对象&#xff0c;并且将其赋值给成员变量&#xff0c;完成依赖注入。 AutoWire…

自动化运维(k8s)之微服务信息自动抓取:namespaceName、deploymentName等全解析

前言&#xff1a;公司云原生k8s二开工程师发了一串通用性命令用来查询以下数值&#xff0c;我想着能不能将这命令写成一个自动化脚本。 起初设计的 版本一&#xff1a;开头加一条环境变量&#xff0c;执行脚本后&#xff0c;提示输入&#xff1a;需要查询的命名空间&#xff0c…

[Python/网络安全] Git漏洞之Githack工具基本安装及使用详析

前言 本文仅分享Githack工具基本安装及使用相关知识&#xff0c;不承担任何法律责任。 Git是一个非常流行的开源分布式版本控制系统&#xff0c;它被广泛用于协同开发和代码管理。许多网站和应用程序都使用Git作为其代码管理系统&#xff0c;并将其部署到生产环境中以维护其代…

解决水库安全监测难题 长期无外接电源 低功耗设备智能化监测系统

解决水库安全监测难题 长期无外接电源 低功耗设备智能化监测系统 国内某水库安全监测项目需要监测点分散&#xff0c;且无外接供电。项目年限为4年&#xff0c;不允许使用太阳能电板。因此&#xff0c;我们需要设备具备低功耗且内置电池的功能。为了满足客户的要求&#xff0c;…

蓝桥杯c++算法秒杀【6】之动态规划【上】(数字三角形、砝码称重(背包问题)、括号序列、组合数问题:::非常典型的必刷例题!!!)

下将以括号序列、组合数问题超级吧难的题为例子讲解动态规划 别忘了请点个赞收藏关注支持一下博主喵&#xff01;&#xff01;&#xff01;! ! ! ! &#xff01; 关注博主&#xff0c;更多蓝桥杯nice题目静待更新:) 动态规划 一、数字三角形 【问题描述】 上图给出了…

AD软件如何快速切换三维视图,由2D切换至3D,以及如何恢复

在Altium Designer软件中&#xff0c;切换三维视图以及恢复二维视图的操作相对简单。以下是具体的步骤&#xff1a; 切换三维视图 在PCB设计界面中&#xff0c;2D切换3D&#xff0c;快捷键按住数字键盘中的“3”即可切换&#xff1b; 快捷键ctrlf&#xff08;或者vb快捷键也…

学习threejs,使用CubeCamera相机创建反光效果

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️CubeCamera 立方体相机 二、…

长时间无事可做是个危险信号

小马加入的是技术开发部&#xff0c;专注于Java开发。团队里有一位姓隋的女同事&#xff0c;是唯一的web前端工程师&#xff0c;负责页面开发工作&#xff0c;比小马早两个月入职。公司的项目多以定制化OA系统为主&#xff0c;后端任务繁重&#xff0c;前端工作相对较少。在这样…

Llama模型分布式训练(微调)

1 常见大模型 1.1 参数量对照表 模型参数量发布时间训练的显存需求VGG-19143.68M2014~5 GB&#xff08;单 224x224 图像&#xff0c;batch_size32&#xff09;ResNet-15260.19M2015~7 GB&#xff08;单 224x224 图像&#xff0c;batch_size32&#xff09;GPT-2 117M117M2019~…

Linux 子进程 -- fork函数

子进程 什么是子进程? 子进程指的是由一个已经存在的进程&#xff08;称为父进程或父进程&#xff09;创建的进程. 如: OS (操作系统) 就可以当作是一个进程, 用来管理软硬件资源, 当我点击浏览器, 想让浏览器运行起来时, 实际上是由 OS 接收指令, 然后 OS 帮我们将浏览器运行…

DataLoade类与list ,iterator ,yield的用法

1 问题 探索DataLoader的属性&#xff0c;方法 Vscode中图标含意 list 与 iterator 的区别&#xff0c;尤其yield的用法 2 方法 知乎搜索DataLoader的属性&#xff0c;方法 pytorch基础的dataloader类是 from torch.utils.data.dataloader import Dataloader 其主要的参数如下&…

C++入门——“C++11-lambda”

引入 C11支持lambda表达式&#xff0c;lambda是一个匿名函数对象&#xff0c;它允许在函数体中直接定义。 一、初识lambda lambda的结构是&#xff1a;[ ] () -> 返回值类型 { }。从左到右依次是&#xff1a;捕捉列表 函数参数 -> 返回值类型 函数体。 以下是一段用lam…

【Linux网络编程】第二弹---Socket编程入门指南:从IP、端口号到传输层协议及编程接口全解析

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】【Linux网络编程】 目录 1、Socket 编程预备 1.1、理解源 IP 和目的 IP 1.2、认识端口号 1.2.1、端口号范围划分 1.2.2、理解 &q…

《用Python实现3D动态旋转爱心模型》

简介 如果二维的爱心图案已经无法满足你的创意&#xff0c;那今天的内容一定适合你&#xff01;通过Python和matplotlib库&#xff0c;我们可以实现一个动态旋转的3D爱心模型&#xff0c;充满立体感和动感。# 实现代码&#xff08;完整代码底部名片私信&#xff09; 以下是完…

shell-函数调用进阶即重定向

shell-函数调用进阶 声明&#xff01; 学习视频来自B站up主 泷羽sec 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及泷…