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);

    }
   
}
posted @ 2025-12-23 13:16  安_宁  阅读(1)  评论(0)    收藏  举报