
上一节已经建好了实体类:Model/Student.cs,并建立了数据库。
_Layout.cshtml 中添加页面跳转路径:

1、StudentPage/Index.cshtml
典型的学生管理页面,实现了列表展示、搜索和删除功能。
右键-->选中添加-->选中Razor页面-->


前端代码:
html
@page
@model RazorStudentManager.Pages.StudentPage.IndexModel
<br />
<div class="row">
<h1 class="text-info col-4"> 学生列表 </h1>
</div>
<div class=" container p-0 m-0 ">
<div class="row">
<div class="col-4">
<form method="get">
<div class="input-group">
<input class="form-control" asp-for="Search" placeholder="请输入姓名查询" />
<div class="input-group-append">
<button type="submit" class="btn btn-primary">查询</button>
</div>
</div>
</form>
</div>
<div class="col-2 offset-6">
<a asp-page="Create" class="btn btn-primary form-control text-white">创建学生</a>
</div>
</div>
<form method="post">
<table class="table m-2">
<thead class="table-light">
<tr>
<th>
<label scope="col" asp-for="Students.FirstOrDefault().Id"></label>
</th>
<th>
<label scope="col" asp-for="Students.FirstOrDefault().Name"></label>
</th>
<th>
<label scope="col" asp-for="Students.FirstOrDefault().Gender"></label>
</th>
<th>
<label scope="col" asp-for="Students.FirstOrDefault().Age"></label>
</th>
<th>
<label scope="col" asp-for="Students.FirstOrDefault().Phone"></label>
</th>
<th>
<label scope="col" asp-for="Students.FirstOrDefault().Address"></label>
</th>
<th>
<label scope="col" asp-for="Students.FirstOrDefault().Description"></label>
</th>
<th>
<label scope="col"> 操作</label>
</th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.Students)
{
<tr>
<th scope="row">@item.Id</th>
<td>@item.Name</td>
<td>@item.Gender</td>
<td>@item.Age</td>
<td>@item.Phone</td>
<td>@item.Address</td>
<td>@item.Description</td>
<td>
<button asp-page-handler="Delete" asp-route-id="@item.Id" class="btn btn-danger btn-sm" onclick="return confirm('您确定要删除吗??')">删除</button>
<a asp-route-id="@item.Id" asp-page="Edit" class="btn btn-success btn-sm">修改</a>
</td>
</tr>
}
</tbody>
</table>
</form>
</div>
后端代码:
cs
/**
* : PageModel: 继承自 PageModel 基类
* 提供 Razor Pages 核心功能:ModelState、ViewData、Redirect 等
* 包含 HTTP 请求处理方法:OnGet()、OnPost() 等
*/
public class IndexModel : PageModel
{
/**
* 私有字段声明 - 依赖注入:
* 作用:声明数据库上下文依赖
*
* private:访问修饰符,只能在当前类中访问
* readonly:只读字段,只能在构造函数中赋值
* AppDbContext:Entity Framework Core 的数据库上下文类型
* _db:字段名(C# 字段命名约定(下划线前缀 + 驼峰命名))
*
* Java对应:private final AppDbContext _db;
*/
private readonly AppDbContext _db;
/**
* 构造函数 - 依赖注入
* 作用:通过构造函数注入依赖
*
* 依赖注入模式: ASP.NET Core 自动创建 AppDbContext 实例并传入
* 生命周期: 默认为 Scoped(每个HTTP请求一个实例)
*
* Java/Spring对应:@Autowired private AppDbContext db;
*/
public IndexModel(AppDbContext db)
{
_db = db; // 将注入的数据库上下文赋值给私有字段
}
/**
* 公共属性 - 学生列表(用于视图显示)
*
* 可在 Razor 视图中访问:@Model.Students
* IEnumerable<Student>: 只读集合接口,支持迭代
*
* 作用: 将数据从 PageModel 传递到 Razor 视图
*/
public IEnumerable<Student> Students { get; set; }
/**
* 绑定属性 - 搜索关键字[前端 asp-for="Search" ]
*
* [BindProperty]: 模型绑定特性,自动将请求参数绑定到属性
* GET: ?search=关键字
* POST: 表单字段 <input name="Search">
* SupportsGet = true: 允许从 GET 请求绑定(默认只支持POST)
* 通过设置 SupportsGet = true,可以扩展绑定功能,使属性也能接收 GET 请求中的查询字符串参数
* 空值处理: 如果请求中没有 Search 参数,属性为 null
*/
[BindProperty(SupportsGet = true)]
public string Search { get; set; }
/**
* HTTP GET 请求处理方法(查询操作)[命名约定: On + HTTP方法名]
*
* async Task: 异步方法,不阻塞线程
* 调用时机: 页面首次加载或 GET 请求时自动调用
*
* 返回值: 通常为 void 或 Task(默认渲染同名页面)
*/
public async Task OnGet()
{
/**
* 创建查询对象:
*
* _db.Students: 访问 Students DbSet(数据库表)
* AsNoTracking(): 重要优化方法!
* 作用: 告诉 EF Core 不跟踪实体变更
* 适用场景: 只读查询,不修改数据
* 性能优势: 减少内存占用,提高查询速度
* 生成的SQL: 没有变化,只是影响 EF Core 内部行为
*/
var query = _db.Students.AsNoTracking();
/*
* 搜索条件处理
*
* string.IsNullOrEmpty(): 检查字符串是否为 null 或空
* query.Where(): LINQ 条件过滤
* Lambda表达式: s => s.Name.Contains(Search)
* s: 每个 Student 对象
* s.Name.Contains(Search): 判断姓名是否包含搜索词
* SQL转换: 生成 WHERE Name LIKE '%{Search}%'
*/
if (!string.IsNullOrEmpty(Search))
{
query = query.Where(s => s.Name.Contains(Search));
}
/*
* 执行查询并赋值给属性
*
* ToListAsync(): 异步执行查询并转换为列表
* 延迟执行: 直到调用 ToListAsync() 才真正查询数据库
* 异步等待: await 释放线程,等待数据库响应
* 赋值: 将查询结果赋值给 Students 属性
*/
Students = await query.ToListAsync();
}
/**
* HTTP POST 请求处理方法(删除操作)[命名约定: OnPost + 操作名(Delete)]
*
* 路由匹配: 表单提交时根据 asp-page-handler="Delete" 调用
* 参数绑定: int id 自动从请求参数绑定
*
* 返回值: IActionResult(重定向、视图、状态码等)
*/
public async Task<IActionResult> OnPostDelete(int id)
{
/*
* 根据ID查找学生实体
*
* FindAsync(id): EF Core 的特殊查找方法
* 先检查本地缓存,再查询数据库,只能根据主键查找,只能根据主键查找
*
* 等价于: _db.Students.FirstOrDefaultAsync(s => s.Id == id)
* SQL: SELECT TOP(1) * FROM Students WHERE Id = @id
*/
var student = await _db.Students.FindAsync(id);
/**
* 找不到实体的处理
*
* NotFound(): ControllerBase 方法,返回 404 状态码
* 防止空引用异常: 避免对 null 对象进行操作
* 用户体验: 告知用户资源不存在
*/
if (student == null)
{
return NotFound(); // 返回404状态码
}
/**
* 标记删除
*
* Remove(): 将实体标记为删除状态
* 重要: 此时还没删除数据库记录!
* 内存操作: 只修改 EF Core 的变更跟踪器状态
*/
_db.Students.Remove(student);
/**
* 将删除操作保存到数据库
*
* SaveChangesAsync(): 提交所有挂起的更改到数据库
* 批量操作: 可以同时处理多个添加、更新、删除
* 事务性: 默认在事务中执行,失败则回滚
*/
await _db.SaveChangesAsync();
/**
* 重定向回当前页面(刷新列表)
*
* 作用: 执行 PRG 模式(Post-Redirect-Get)
* POST 处理完成后重定向到 GET,防止表单重复提交,刷新页面显示最新数据
* */
return RedirectToPage();
}
}
运行结果:

2、StudentPage/Create.cshtml
前端代码:
html
@page
@model RazorStudentManager.Pages.StudentPage.CreateModel
<br />
<h1 class="text-info"> Create </h1>
<br />
<div class="border container p-4">
<form method="post">
<div class="form-group row mb-3">
<div class="col-3">
<label asp-for="Student.Name"></label>
</div>
<div class="col-6">
<input class="form-control" asp-for="Student.Name" />
</div>
<span asp-validation-for="Student.Name" class="text-danger"></span>
</div>
<div class="form-group row mb-3">
<div class="col-3">
<label asp-for="Student.Gender"></label>
</div>
<div class="col-6">
<select class="form-select" asp-for="Student.Gender" asp-items="Html.GetEnumSelectList<Gender>()">
<option value="">请选择性别</option>
</select>
</div>
<span asp-validation-for="Student.Gender" class="text-danger"></span>
</div>
<div class="form-group row mb-3">
<div class="col-3">
<label asp-for="Student.Age"></label>
</div>
<div class="col-6">
<input class="form-control" asp-for="Student.Age" />
</div>
<span asp-validation-for="Student.Age" class="text-danger"></span>
</div>
<div class="form-group row mb-3">
<div class="col-3">
<label asp-for="Student.Phone"></label>
</div>
<div class="col-6">
<input class="form-control" asp-for="Student.Phone" />
</div>
<span asp-validation-for="Student.Phone" class="text-danger"></span>
</div>
<div class="form-group row mb-3">
<div class="col-3">
<label asp-for="Student.Address"></label>
</div>
<div class="col-6">
<input class="form-control" asp-for="Student.Address" />
</div>
</div>
<div class="form-group row mb-3">
<div class="col-3">
<label asp-for="Student.Description"></label>
</div>
<div class="col-6">
<input class="form-control" asp-for="Student.Description" />
</div>
</div>
<div class="form-group row mb-3">
<div class="col-3 offset-3">
<input type="submit" value="创建" class="btn btn-primary form-control" />
</div>
<div class="col-3">
<a asp-page="Index" class="btn btn-success form-control text-white">返回</a>
</div>
</div>
</form>
</div>
后端代码:
cs
public class CreateModel : PageModel
{
private readonly AppDbContext _db;
public CreateModel(AppDbContext db)
{
_db = db;//在构造里注入上下文
}
[BindProperty] //前后端绑定
public Student Student { get; set; }
public async Task<IActionResult> OnPost()
{
// ModelState.IsValid 是 ASP.NET MVC 中用于验证模型状态的属性,表示当前模型是否满足所有验证规则(如Required、StringLength等特性)。
// 若验证通过返回 true,否则返回 false。
if (ModelState.IsValid)
{
await _db.AddAsync(Student); //将Student实体信息添加到数据库上下文
await _db.SaveChangesAsync();//执行到数据库
return RedirectToPage("Index");//重定向到Index页面
}
else
{
return Page();
}
}
}
运行结果:

3、StudentPage/Edit.cshtml
前端代码:
html
@page
@model RazorStudentManager.Pages.StudentPage.EditModel
<br />
<h1 class="text-info"> Edit </h1>
<br />
<div class="border container p-4">
<form method="post">
<input type="hidden" asp-for="Student.Id" />
<div class="form-group row mb-3">
<div class="col-3">
<label asp-for="Student.Name"></label>
</div>
<div class="col-6">
<input class="form-control" asp-for="Student.Name" />
</div>
<span asp-validation-for="Student.Name" class="text-danger"></span>
</div>
<div class="form-group row mb-3">
<div class="col-3">
<label asp-for="Student.Gender"></label>
</div>
<div class="col-6">
<select class="form-select" asp-for="Student.Gender" asp-items="Html.GetEnumSelectList<Gender>()">
<option value="">请选择性别</option>
</select>
</div>
<span asp-validation-for="Student.Gender" class="text-danger"></span>
</div>
<div class="form-group row mb-3">
<div class="col-3">
<label asp-for="Student.Age"></label>
</div>
<div class="col-6">
<input class="form-control" asp-for="Student.Age" />
</div>
<span asp-validation-for="Student.Age" class="text-danger"></span>
</div>
<div class="form-group row mb-3">
<div class="col-3">
<label asp-for="Student.Phone"></label>
</div>
<div class="col-6">
<input class="form-control" asp-for="Student.Phone" />
</div>
<span asp-validation-for="Student.Phone" class="text-danger"></span>
</div>
<div class="form-group row mb-3">
<div class="col-3">
<label asp-for="Student.Address"></label>
</div>
<div class="col-6">
<input class="form-control" asp-for="Student.Address" />
</div>
</div>
<div class="form-group row mb-3">
<div class="col-3">
<label asp-for="Student.Description"></label>
</div>
<div class="col-6">
<input class="form-control" asp-for="Student.Description" />
</div>
</div>
<div class="form-group row mb-3">
<div class="col-3 offset-3">
<input type="submit" value="修改" class="btn btn-primary form-control" />
</div>
<div class="col-3">
<a asp-page="Index" class="btn btn-success form-control text-white">返回</a>
</div>
</div>
</form>
</div>
后端代码:
cs
public class EditModel : PageModel
{
private readonly AppDbContext _db;
public EditModel(AppDbContext db)
{
_db = db;
}
[BindProperty]
public Student Student { get; set; }
public async Task OnGet(int id)
{
//加载单个学生的信息
Student = await _db.Students.FindAsync(id);
}
public async Task<IActionResult> OnPost()
{
if (ModelState.IsValid)
{
var studentObj = await _db.Students.FindAsync(Student.Id);
studentObj.Name = Student.Name;
studentObj.Gender = Student.Gender;
studentObj.Age = Student.Age;
studentObj.Phone = Student.Phone;
studentObj.Address = Student.Address;
studentObj.Description = Student.Description;
await _db.SaveChangesAsync();
return RedirectToPage("Index");
}
return RedirectToPage();
}
}
运行结果:
