DncZeus实战开源项目(五)CRUD操作演示
CRUD接口实例---NvrServer
- 新建实体类
// NvrServer.cs
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using static DncZeus.Api.Entities.Enums.CommonEnum;
namespace DncZeus.Api.Entities
{
public class NvrServer
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
[StringLength(50)]
public string Name { get; set; }
[Required]
[StringLength(50)]
public string IP { get; set; }
[StringLength(100)]
public string Notice { get; set; }
public IsDeleted IsDeleted { get; set; }
public DateTime CreateTime { get; set; }
public DateTime? UpdateTime { get; set; }
// 数据库导航属性:使用 virtual 以支持延迟加载
public virtual ICollection<Camera> Cameras { get; set; }
}
}
- 在
dbContext中注册并映射到数据库
// DncAuthDbContext.cs
using Microsoft.EntityFrameworkCore;
namespace DncZeus.Api.Entities
{
public class DncZeusDbContext : DbContext
{
......
public DbSet<NvrServer> NvrServer { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
......
modelBuilder.Entity<NvrServer>(entity =>
{
entity.HasKey(e => e.Id);
entity.Property(e => e.Name).IsRequired();
entity.Property(e => e.IP).IsRequired();
});
......
base.OnModelCreating(modelBuilder);
}
}
}
- 新建
视图模型ViewModel- 本质就是
模型的序列化- 定义字段的校验规则,序列化字段并返回给前端
- 意义: 当前端传过来的字段不符合要求时,会报错对应的异常
- 本质就是
// ViewModels.Equitments.NvrServer.NvrServerCreateViewModel.cs
using System.ComponentModel.DataAnnotations;
namespace DncZeus.Api.ViewModels.Equitments.NvrServer
{
public class NvrServerCreateViewModel
{
[Required(ErrorMessage = "请输入服务器名称")]
[StringLength(50, ErrorMessage = "服务器名称长度不能超过50个字符")]
public string Name { get; set; }
[Required(ErrorMessage = "请输入IP地址")]
[StringLength(50, ErrorMessage = "IP地址长度不能超过50个字符")]
public string IP { get; set; }
[StringLength(100, ErrorMessage = "备注长度不能超过100个字符")]
public string Notice { get; set; }
}
}
// NvrServerEditViewModel.cs
using System.ComponentModel.DataAnnotations;
namespace DncZeus.Api.ViewModels.Equitments.NvrServer
{
public class NvrServerEditViewModel
{
public int Id { get; set; }
[Required(ErrorMessage = "请输入服务器名称")]
[StringLength(50, ErrorMessage = "服务器名称长度不能超过50个字符")]
public string Name { get; set; }
[Required(ErrorMessage = "请输入IP地址")]
[StringLength(50, ErrorMessage = "IP地址长度不能超过50个字符")]
public string IP { get; set; }
[StringLength(100, ErrorMessage = "备注长度不能超过100个字符")]
public string Notice { get; set; }
public bool IsDeleted { get; set; }
}
}
// NvrServerJsonModel.cs
namespace DncZeus.Api.ViewModels.Equitments.NvrServer
{
public class NvrServerJsonModel
{
public int Id { get; set; }
public string Name { get; set; }
public string IP { get; set; }
public string Notice { get; set; }
public bool IsDeleted { get; set; }
public string CreateTime { get; set; }
public string UpdateTime { get; set; }
public int CameraCount { get; set; }
}
}
- 新建
请求模型- 本质就是
分页,排序和关键字搜索- 基类
RequestPayload已自带分页和排序
- 基类
- 本质就是
// RequestPayload.Equitments.NvrServer.cs
using DncZeus.Api.RequestPayload;
namespace DncZeus.Api.RequestPayload.Equitments.NvrServer
{
public class NvrServerRequestPayload:RequestPayload
{
public string Kw { get; set; }
}
}
-
AutoMapper配置映射-
作用
- 在不同类型之间自动转换,避免手动赋值
// 没有 AutoMapper 时 var jsonModel = new UserJsonModel { Id = user.Id, Name = user.Name, // ... 需要手动赋值每个属性 }; // 使用 AutoMapper var jsonModel = _mapper.Map<DncUser, UserJsonModel>(user); // 自动转换- 配置映射规则: 定义
实体和ViewModel之间的关系
// 基本映射 CreateMap<DncUser, UserJsonModel>(); // 复杂映射(自定义字段映射) CreateMap<DncPermission, PermissionJsonModel>() .ForMember(d => d.MenuName, s => s.MapFrom(x => x.Menu.Name)) // 关联表字段 .ForMember(d => d.PermissionTypeText, s => s.MapFrom(x => x.Type.ToString())); // 类型转文本- 支持
实体↔ViewModel的双向转换:
// 实体 → ViewModel CreateMap<DncUser, UserEditViewModel>(); // ViewModel → 实体 CreateMap<UserEditViewModel, DncUser>();- 实际应用
// 查询列表 var data = list.Select(_mapper.Map<DncUser, UserJsonModel>); // 创建时映射 var entity = _mapper.Map<UserCreateViewModel, DncUser>(model); // 编辑时映射 entity.DisplayName = model.DisplayName; // 手动赋值 // 或者 entity = _mapper.Map<UserEditViewModel, DncUser>(model); // 自动映射
-
-
CRUD接口
// V1.Equitments.NvrServer.cs
using AutoMapper;
using DncZeus.Api.Entities;
using DncZeus.Api.Entities.Enums;
using DncZeus.Api.Extensions;
using DncZeus.Api.Extensions.AuthContext;
using DncZeus.Api.Extensions.DataAccess;
using DncZeus.Api.Models.Response;
using DncZeus.Api.RequestPayload.Equitments.NvrServer;
using DncZeus.Api.ViewModels.Equitments.NvrServer;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using static DncZeus.Api.Entities.Enums.CommonEnum;
namespace DncZeus.Api.Controllers.Api.V1.Equitments.NvrServer
{
[Route("api/v1/nvrserver/[action]")]
[ApiController]
public class NvrServerController : ControllerBase
{
private readonly DncZeusDbContext _dbContext;
private readonly IMapper _mapper;
// 注入dbContext和mapper
public NvrServerController(DncZeusDbContext dbContext, IMapper mapper)
{
_dbContext = dbContext;
_mapper = mapper;
}
[HttpPost]
public IActionResult List(NvrServerRequestPayload payload)
/* payload是个对象
{
"pageSize": 6,
"currentPage": 1,
"sort": [
{
"field": "Name",
"direct": "DESC"
}
],
"kw": "服务器"
}
*/
{
using (_dbContext)
{
// 获取数据库所有的记录集
var query = _dbContext.Set<Entities.NvrServer>().AsQueryable();
// 筛选未删除的记录
query = query.Where(x => x.IsDeleted == IsDeleted.No);
// 当Kw不为空值时,搜索查询
if (!string.IsNullOrEmpty(payload.Kw))
{
query = query.Where(x => x.Name.Contains(payload.Kw.Trim()) ||
x.IP.Contains(payload.Kw.Trim()) ||
(x.Notice != null && x.Notice.Contains(payload.Kw.Trim())));
}
// 排序
if (payload.FirstSort != null)
{
// 验证排序字段是否有效
var validFields = new[] { "Id", "Name", "IP", "Notice", "IsDeleted", "CreateTime", "UpdateTime" };
if (!string.IsNullOrEmpty(payload.FirstSort.Field) && validFields.Contains(payload.FirstSort.Field))
{
query = query.OrderBy(payload.FirstSort.Field, payload.FirstSort.Direct == "DESC");
}
}
// 先获取总数
var totalCount = query.Count();
// 获取分页数据
var list = query.Paged(payload.CurrentPage, payload.PageSize).ToList();
// 获取所有相关ID
var nvrIds = list.Select(x => x.Id).ToList();
// 批量查询摄像头数量
var cameraCounts = _dbContext.Camera
.Where(c => nvrIds.Contains(c.NvrServerId) && c.IsDeleted == IsDeleted.No)
.GroupBy(c => c.NvrServerId)
.ToDictionary(g => g.Key, g => g.Count());
// 在 using 块内完成所有数据映射
var data = list.Select(x =>
{
var model = _mapper.Map<DncZeus.Api.Entities.NvrServer, NvrServerJsonModel>(x);
model.CreateTime = x.CreateTime.ToString("yyyy-MM-dd HH:mm:ss");
model.UpdateTime = x.UpdateTime?.ToString("yyyy-MM-dd HH:mm:ss");
model.CameraCount = cameraCounts.GetValueOrDefault(x.Id, 0);
return model;
}).ToList();
var response = ResponseModelFactory.CreateResultInstance;
response.SetData(data, totalCount);
return Ok(response);
}
}
// 测试接口,返回所有的数据(不分页)
[HttpGet("debug")]
public IActionResult GetAllDebug()
{
using (_dbContext)
{
var allRecords = _dbContext.NvrServer
.Select(x => new { x.Id, x.Name, x.IsDeleted, x.CreateTime })
.ToList();
var response = ResponseModelFactory.CreateInstance;
response.SetData(new { AllRecords = allRecords, TotalCount = allRecords.Count });
return Ok(response);
}
}
// create接口
[HttpPost]
public IActionResult Create(NvrServerCreateViewModel model)
{
var response = ResponseModelFactory.CreateInstance;
using (_dbContext)
{
if (_dbContext.NvrServer.Any(x => x.Name == model.Name.Trim()))
{
response.SetFailed("服务器名称已存在");
return Ok(response);
}
if (_dbContext.NvrServer.Any(x => x.IP == model.IP.Trim()))
{
response.SetFailed("IP地址已存在");
return Ok(response);
}
/*利用mapper快速生成entity(若校验不通过会自动触发异常,无需再try)
{
"errors": {
"IP": [
"请输入IP地址"
]
},
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "00-b80c95c5799d733934eb6ac53c69025c-6787641c69bfb97c-00"
}
*/
var entity = _mapper.Map<NvrServerCreateViewModel, Entities.NvrServer>(model);
entity.CreateTime = DateTime.Now;
entity.IsDeleted = IsDeleted.No;
_dbContext.NvrServer.Add(entity);
_dbContext.SaveChanges();
response.SetSuccess();
return Ok(response);
}
}
// 获取单个实体
[HttpGet("{id}")]
public IActionResult Edit(int id) {
var entity = _dbContext.NvrServer.FirstOrDefault(x => x.Id == id);
if (entity == null) {
return NotFound();
}
var response = ResponseModelFactory.CreateInstance;
response.SetData(_mapper.Map<Entities.NvrServer,NvrServerEditViewModel>(entity));
return Ok(response);
}
[HttpPost]
public IActionResult Edit(NvrServerEditViewModel model)
{
var response = ResponseModelFactory.CreateInstance;
using (_dbContext) {
var entity = _dbContext.NvrServer.FirstOrDefault(x => x.Id == model.Id);
if (entity == null)
{
response.SetFailed("服务器不存在");
return Ok(response);
}
if (_dbContext.NvrServer.Any(x => x.Name == model.Name.Trim() && x.Id != model.Id))
{
response.SetFailed("服务器名称已存在");
return Ok(response);
}
if (_dbContext.NvrServer.Any(x => x.IP == model.IP.Trim() && x.Id != model.Id))
{
response.SetFailed("IP地址已存在");
return Ok(response);
}
entity.Name = model.Name;
entity.IP = model.IP;
entity.Notice = model.Notice;
// entity.IsDeleted = model.IsDeleted;
entity.IsDeleted = model.IsDeleted ? CommonEnum.IsDeleted.Yes : CommonEnum.IsDeleted.No;
entity.UpdateTime = DateTime.Now;
_dbContext.SaveChanges();
response.SetSuccess();
return Ok(response);
}
}
[HttpGet("{ids}")]
public IActionResult Delete(string ids)
{
var response = UpdateIsDelete(IsDeleted.Yes, ids);
return Ok(response);
}
[HttpGet("{ids}")]
public IActionResult Recover(string ids)
{
var response = UpdateIsDelete(IsDeleted.No, ids);
return Ok(response);
}
[HttpGet]
public IActionResult GetAll()
{
using (_dbContext)
{
var list = _dbContext.NvrServer
.Where(x => x.IsDeleted == IsDeleted.No)
.Select(x => new { x.Id, x.Name })
.ToList();
var response = ResponseModelFactory.CreateInstance;
response.SetData(list);
return Ok(response);
}
}
// 批量删除
private ResponseModel UpdateIsDelete(IsDeleted isDeleted, string ids)
{
var response = ResponseModelFactory.CreateInstance;
var idList = ids.Split(",").Select(x => int.Parse(x)).ToList();
using (_dbContext)
{
var servers = _dbContext.NvrServer.Where(x => idList.Contains(x.Id)).ToList();
foreach (var server in servers)
{
server.IsDeleted = isDeleted;
server.UpdateTime = DateTime.Now;
}
_dbContext.SaveChanges();
return response;
}
}
}
}
Edit接口代码优化
- 针对
public IActionResult Edit(NvrServerEditViewModel model)接口里面的手动赋值,这里可以利用mapper实现更简洁的代码
// MappingProfile.cs
......
// 新增
CreateMap<NvrServerEditViewModel, NvrServer>()
.ForMember(dest => dest.CreateTime, opt => opt.Ignore())
.ForMember(dest => dest.UpdateTime, opt => opt.Ignore())
.ForMember(dest => dest.IsDeleted, opt => opt.MapFrom(src => src.IsDeleted ? IsDeleted.Yes : IsDeleted.No));
// 原先
CreateMap<NvrServer, NvrServerEditViewModel>()
.ForMember(dest => dest.IsDeleted, opt => opt.MapFrom(src => src.IsDeleted==IsDeleted.Yes));
// 接口.cs
public IActionResult Edit(NvrServerEditViewModel model)
{
......
using (_dbContext) {
var entity = _dbContext.NvrServer.FirstOrDefault(x => x.Id == model.Id);
......
//entity.Name = model.Name;
//entity.IP = model.IP;
//entity.Notice = model.Notice;
////entity.IsDeleted = model.IsDeleted;
//entity.IsDeleted = model.IsDeleted ? CommonEnum.IsDeleted.Yes : CommonEnum.IsDeleted.No;
//entity.UpdateTime = DateTime.Now;
// 使用AutoMapper映射到现有实体
_mapper.Map(model, entity);
// 手动赋值(不想赋值也可以,mapper再做一个配置即可)
entity.UpdateTime = DateTime.Now;
_dbContext.SaveChanges();
response.SetSuccess();
return Ok(response);
}
}

浙公网安备 33010602011771号