.NET Core MongoDB数据仓储和工作单元模式实操

前言

上一章节我们主要讲解了MongoDB数据仓储和工作单元模式的封装,这一章节主要讲的是MongoDB用户管理相关操作实操。如:获取所有用户信息、获取用户分页数据、通过用户ID获取对应用户信息、添加用户信息、事务添加用户信息、用户信息修改、用户信息删除等实战教程。

MongoDB从入门到实战的相关教程

MongoDB从入门到实战之MongoDB简介👉

MongoDB从入门到实战之MongoDB快速入门👉

MongoDB从入门到实战之Docker快速安装MongoDB👉

MongoDB从入门到实战之MongoDB工作常用操作命令👉

MongoDB从入门到实战之.NET Core使用MongoDB开发ToDoList系统(1)-后端项目框架搭建👉

MongoDB从入门到实战之.NET Core使用MongoDB开发ToDoList系统(2)-Swagger框架集成👉

MongoDB从入门到实战之.NET Core使用MongoDB开发ToDoList系统(3)-系统数据集合设计👉

MongoDB从入门到实战之.NET Core使用MongoDB开发ToDoList系统(4)-MongoDB数据仓储和工作单元模式封装👉

MongoDB从入门到实战之.NET Core使用MongoDB开发ToDoList系统(5)-MongoDB数据仓储和工作单元模式实操👉

YyFlight.ToDoList项目源码地址

欢迎各位看官老爷review,有帮助的别忘了给我个Star哦💖!!!

GitHub地址:GitHub - YSGStudyHards/YyFlight.ToDoList: 【.NET8 MongoDB 待办清单系统】.NET8 MongoDB从入门到实战基础教程,该项目后端使用的是.NET8、前端页面使用Blazor、使用MongoDB存储数据,更多相关内容大家可以看目录中的MongoDB从入门到实战的相关教程。该系列教程可作为.NET Core入门项目进行学习,感兴趣的小伙伴可以关注博主和我一起学习共同进步。

MongoRepository地址:https://github.com/YSGStudyHards/YyFlight.ToDoList/tree/main/Repository/Repository

MongoDB事务使用前提说明

参阅MongoDB的事务👉

说明:

MongoDB单机服务器不支持事务【使用MongoDB事务会报错:Standalone servers do not support transactions】,只有在集群情况下才支持事务,因为博主接下来都是在单机环境下操作,所以无法来演示Mongo事务操作,但是方法都已经是封装好了的,大家可以自己搭建集群实操。

原因:

MongoDB在使用分布式事务时需要进行多节点之间的协调和通信,而单机环境下无法实现这样的分布式协调和通信机制。但是,在MongoDB部署为一个集群(cluster)后,将多个计算机连接为一个整体,通过协调和通信机制实现了分布式事务的正常使用。从数据一致性和可靠性的角度来看,在分布式系统中实现事务处理是至关重要的。而在单机环境下不支持事务,只有在集群情况下才支持事务的设计方式是为了保证数据一致性和可靠性,并且也符合分布式系统的设计思想。

创建EntityBase公共类

一个公共的具有相同特性和行为的基类。

复制代码
    public class EntityBase
    {
        /// <summary>
        /// 主键Id
        /// </summary>
        [BsonId]
        [BsonRepresentation(BsonType.ObjectId)]
        public string Id { get; set; }

        /// <summary>
        /// 创建时间
        /// </summary>
        public DateTime CreateDate { get; set; }

        /// <summary>
        /// 更新时间
        /// </summary>
        public DateTime UpdateDate { get; set; }
    }

添加UserInfo用户表实体映射模型

复制代码
    [Table("yyflight_todolist_user")]
    public class UserInfo : EntityBase
    {
        /// <summary>
        /// 登录账号
        /// </summary>
        public string UserName { get; set; }

        /// <summary>
        /// 登录密码
        /// </summary>

        public string Password { get; set; }

        /// <summary>
        /// 用户昵称
        /// </summary>
        public string NickName { get; set; }

        /// <summary>
        /// 用户头像
        /// </summary>
        public string HeadPortrait { get; set; }

        /// <summary>
        /// 用户邮箱
        /// </summary>
        public string Email { get; set; }

        /// <summary>
        /// 用户状态(0冻结,1正常,2注销)
        /// </summary>
        public int Status { get; set; }
    }

在前面类中,Id属性中的特性的作用:

  • 需要用于将通用语言运行时(CLR)对象映射到MongoDB集合。
  • [BsonId]进行注释,使该属性成为文档的主键。
  • [BsonRepresentation(BsonType.ObjectId)]进行注释,以允许以字符串类型而不是ObjectId结构传递参数。Mongo处理从字符串到ObjectId的转换。没有此特性序列化时会有如下异常提示:

System.FormatException: An error occurred while deserializing the Id property of class Repository.Domain.User.UserInfo: Cannot deserialize a 'String' from BsonType 'ObjectId'.

知识拓展MongoDB ObjectId类型概述:

每次插入一条数据系统都会自动插入一个_id键,键值不可以重复,它可以是任何类型的,也可以手动的插入,默认情况下它的数据类型是ObjectId,由于MongoDB在设计之初就是用作分布式数据库,所以使用ObjectId可以避免不同数据库中_id的重复(如果使用自增的方式在分布式系统中就会出现重复的_id的值)。

ObjectId使用12字节的存储空间,每个字节可以存储两个十六进制数字,所以一共可以存储24个十六进制数字组成的字符串,在这24个字符串中,前8位表示时间戳,接下来6位是一个机器码,接下来4位表示进程id,最后6位表示计数器。

MongoDB 采用 ObjectId 来表示主键的类型,数据库中每个文档都拥有一个_id 字段表示主键,_id 的生成规则如下:

其中包括4-byte Unix 时间戳,3-byte 机器 ID,2-byte 进程 ID,3-byte 计数器(初始化随机)

复制代码
601e2b6b  a3203c  c89f   2d31aa
   ↑        ↑       ↑       ↑
 时间戳    机器码   进程ID   随机数 

创建用户Repository

创建用户IUserRepository接口

复制代码
    public interface IUserRepository : IMongoRepository<UserInfo>
    {
    }

创建用户UserRepository类

复制代码
    public class UserRepository : MongoBaseRepository<UserInfo>, IUserRepository
    {
        public UserRepository(IMongoContext context) : base(context)
        {
        }
    }

创建用户管理业务代码

创建IUserOperationExampleServices接口

复制代码
    public interface IUserOperationExampleServices
    {
        /// <summary>
        /// 获取所有用户信息
        /// </summary>
        /// <returns></returns>
        Task<IEnumerable<UserInfo>> GetAllUserInfos();

        /// <summary>
        /// 用户分页数据获取
        /// </summary>
        /// <param name="userInfoByPageListReq">userInfoByPageListReq</param>
        /// <returns></returns>
        Task<IEnumerable<UserInfo>> GetUserInfoByPageList(UserInfoByPageListReq userInfoByPageListReq);

        /// <summary>
        /// 通过用户ID获取对应用户信息
        /// </summary>
        /// <param name="id">id</param>
        /// <returns></returns>
        Task<UserInfo> GetUserInfoById(string id);

        /// <summary>
        /// 添加用户信息
        /// </summary>
        /// <param name="userInfo">userInfo</param>
        /// <returns></returns>
        Task<UserInfo> AddUserInfo(UserInfoReq userInfo);

        /// <summary>
        /// 事务添加用户信息
        /// </summary>
        /// <param name="userInfo">userInfo</param>
        /// <returns></returns>
        Task<UserInfo> AddUserInfoTransactions(UserInfoReq userInfo);

        /// <summary>
        /// 用户信息修改
        /// </summary>
        /// <param name="id">id</param>
        /// <param name="userInfo">userInfo</param>
        /// <returns></returns>
        Task<UserInfo> UpdateUserInfo(string id, UserInfoReq userInfo);

        /// <summary>
        /// 用户信息删除
        /// </summary>
        /// <param name="id">id</param>
        /// <returns></returns>
        Task<bool> Delete(string id);
    }

创建UserOperationExampleServices类

复制代码
    public class UserOperationExampleServices : IUserOperationExampleServices
    {
        private readonly IUnitOfWork _unitOfWork;
        private readonly IUserRepository _userRepository;

        /// <summary>
        /// 依赖注入
        /// </summary>
        /// <param name="unitOfWork">unitOfWork</param>
        /// <param name="userRepository">userRepository</param>
        public UserOperationExampleServices(IUnitOfWork unitOfWork, IUserRepository userRepository)
        {
            _unitOfWork = unitOfWork;
            _userRepository = userRepository;
        }

        /// <summary>
        /// 获取所有用户信息
        /// </summary>
        /// <returns></returns>
        public async Task<IEnumerable<UserInfo>> GetAllUserInfos()
        {
            var getAllUserInfos = await _userRepository.GetAllAsync();
            return getAllUserInfos;
        }

        /// <summary>
        /// 用户分页数据获取
        /// </summary>
        /// <param name="userInfoByPageListReq">userInfoByPageListReq</param>
        /// <returns></returns>
        public async Task<IEnumerable<UserInfo>> GetUserInfoByPageList(UserInfoByPageListReq request)
        {
            //创建查询条件构造器
            FilterDefinitionBuilder<UserInfo> buildFilter = Builders<UserInfo>.Filter;
            FilterDefinition<UserInfo> filter = buildFilter.Empty;
            SortDefinition<UserInfo> sort = Builders<UserInfo>.Sort.Ascending(m => m.CreateDate);
            if (!string.IsNullOrEmpty(request.NickName))
            {
                filter = buildFilter.Eq(m => m.NickName, request.NickName);
            }

            if (!string.IsNullOrEmpty(request.Id))
            {
                filter = buildFilter.Eq(m => m.Id, request.Id);
            }

            var list = await _userRepository.FindListByPageAsync(filter, request.PageIndex, request.PageSize, Array.Empty<string>(), sort);
            return list;
        }

        /// <summary>
        /// 通过用户ID获取对应用户信息
        /// </summary>
        /// <param name="id">id</param>
        /// <returns></returns>
        public async Task<UserInfo> GetUserInfoById(string id)
        {
            var getUserInfo = await _userRepository.GetByIdAsync(id);
            return getUserInfo;
        }

        /// <summary>
        /// 添加用户信息
        /// </summary>
        /// <param name="userInfo">userInfo</param>
        /// <returns></returns>
        public async Task<UserInfo> AddUserInfo(UserInfoReq userInfo)
        {
            var addUserInfo = new UserInfo()
            {
                Id = ObjectId.GenerateNewId().ToString(),
                UserName = userInfo.UserName,
                Email = userInfo.Email,
                NickName = userInfo.NickName,
                Password = MD5Helper.MDString(userInfo.Password),
                Status = 1,
                HeadPortrait = userInfo.HeadPortrait,
                CreateDate = DateTime.Now,
                UpdateDate = DateTime.Now,
            };
            await _userRepository.AddAsync(addUserInfo);
            var queryUserInfo = await _userRepository.GetByIdAsync(addUserInfo.Id);
            return queryUserInfo;
        }

        /// <summary>
        /// 事务添加用户信息
        /// </summary>
        /// <param name="userInfo">userInfo</param>
        /// <returns></returns>
        public async Task<UserInfo> AddUserInfoTransactions(UserInfoReq userInfo)
        {
            using var session = await _unitOfWork.InitTransaction();
            var addUserInfo = new UserInfo()
            {
                Id = ObjectId.GenerateNewId().ToString(),
                UserName = userInfo.UserName,
                Email = userInfo.Email,
                NickName = userInfo.NickName,
                Password = MD5Helper.MDString(userInfo.Password),
                Status = 1,
                HeadPortrait = userInfo.HeadPortrait,
                CreateDate = DateTime.Now,
                UpdateDate = DateTime.Now,
            };
            await _userRepository.AddTransactionsAsync(session, addUserInfo);

            //查不到任何信息
            var queryUserInfo = await _userRepository.GetByIdAsync(addUserInfo.Id);

            //提交新增用户信息操作
            await _unitOfWork.Commit(session);

            //UserInfo只有在提交后才会被添加
            queryUserInfo = await _userRepository.GetByIdAsync(addUserInfo.Id);

            return queryUserInfo;
        }

        /// <summary>
        /// 用户信息修改
        /// </summary>
        /// <param name="id">id</param>
        /// <param name="userInfo">userInfo</param>
        /// <returns></returns>
        public async Task<UserInfo> UpdateUserInfo(string id, UserInfoReq userInfo)
        {
            #region 指定字段和条件修改

            //修改条件
            var list = new List<FilterDefinition<UserInfo>>
            {
                Builders<UserInfo>.Filter.Eq("_id", new ObjectId(id))
            };
            var filter = Builders<UserInfo>.Filter.And(list);

            //指定要修改的字段内容
            //参考文章:https://chsakell.gitbook.io/mongodb-csharp-docs/crud-basics/update-documents
            var updateDefinition = Builders<UserInfo>.Update.
                Set(u => u.HeadPortrait, userInfo.HeadPortrait).
                Set(u => u.NickName, userInfo.NickName).
                Set(u => u.Status, userInfo.Status);

            await _userRepository.UpdateAsync(filter, updateDefinition);

            #endregion

            #region 指定对象异步修改一条数据

            //var updateUserInfo = new UserInfo
            //{
            //    UserName = userInfo.UserName,
            //    Password = MD5Helper.MDString(userInfo.Password),
            //    Status = 1,
            //    HeadPortrait = userInfo.HeadPortrait,
            //    Email = userInfo.Email,
            //    NickName = userInfo.NickName,
            //    UpdateDate = DateTime.Now,
            //};
            //await _userRepository.UpdateAsync(updateUserInfo, id);

            #endregion

            #region 数据批量修改示例

            1.批量修改的条件(把创建时间CreateDate为近五日的用户状态更改为0)
            //var time = DateTime.Now;
            //var list = new List<FilterDefinition<UserInfo>>();
            //list.Add(Builders<UserInfo>.Filter.Gt("CreateDate", time));//大于当前时间
            //list.Add(Builders<UserInfo>.Filter.Lt("CreateDate", time.AddDays(5)));//小于当前时间+5day
            //var filter = Builders<UserInfo>.Filter.And(list);

            2.要修改的字段内容
            //var dic = new Dictionary<string, string>
            //{
            //    { "Status", "0" }
            //};

            3.批量修改
            //await _userRepository.UpdateManayAsync(dic, filter);

            #endregion

            return await _userRepository.GetByIdAsync(id);
        }

        /// <summary>
        /// 用户信息删除
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<bool> Delete(string id)
        {
            await _userRepository.DeleteAsync(id);
            var testUserInfo = await _userRepository.GetByIdAsync(id);
            return testUserInfo == null;
        }
    }

UserOperationExample控制创建

复制代码
    /// <summary>
    /// MongoDB用户管理操作示例
    /// </summary>
    [ApiController]
    [Produces("application/json")]
    [Route("api/[controller]/[action]")]
    public class UserOperationExampleController : ControllerBase
    {
        private readonly IUserOperationExampleServices _userOperationExampleServices;

        /// <summary>
        /// 依赖注入
        /// </summary>
        /// <param name="userOperationExampleServices">userOperationExampleServices</param>
        public UserOperationExampleController(IUserOperationExampleServices userOperationExampleServices)
        {
            _userOperationExampleServices = userOperationExampleServices;
        }

        /// <summary>
        /// 获取所有用户信息
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public async Task<ActionResult<IEnumerable<UserInfo>>> GetAllUserInfos()
        {
            var userInfos = await _userOperationExampleServices.GetAllUserInfos();
            return Ok(userInfos);
        }

        /// <summary>
        /// 获取用户分页数据
        /// </summary>
        /// <param name="userInfoByPageListReq">userInfoByPageListReq</param>
        /// <returns></returns>
        [HttpPost]
        public async Task<ActionResult<IEnumerable<UserInfo>>> GetUserInfoByPageList([FromBody] UserInfoByPageListReq userInfoByPageListReq)
        {
            var getUserInfoByPageList = await _userOperationExampleServices.GetUserInfoByPageList(userInfoByPageListReq);
            return Ok(getUserInfoByPageList);
        }

        /// <summary>
        /// 通过用户ID获取对应用户信息
        /// </summary>
        /// <param name="id">id</param>
        /// <returns></returns>
        [HttpGet("{id}")]
        public async Task<ActionResult<UserInfo>> GetUserInfoById(string id)
        {
            var userInfo = await _userOperationExampleServices.GetUserInfoById(id);
            return Ok(userInfo);
        }

        /// <summary>
        /// 添加用户信息
        /// </summary>
        /// <param name="userInfo">userInfo</param>
        /// <returns></returns>
        [HttpPost]
        public async Task<ActionResult<UserInfo>> AddUserInfo([FromBody] UserInfoReq userInfo)
        {
            var addUserInfo = await _userOperationExampleServices.AddUserInfo(userInfo);
            return Ok(addUserInfo);
        }

        /// <summary>
        /// 事务添加用户信息
        /// </summary>
        /// <param name="userInfo">userInfo</param>
        /// <returns></returns>
        [HttpPost]
        public async Task<ActionResult<UserInfo>> AddUserInfoTransactions([FromBody] UserInfoReq userInfo)
        {
            //TODO:单机服务器不支持事务使用【使用MongoDB事务会报错:Standalone servers do not support transactions】,只有在集群情况下才能用
            var addUserInfo = await _userOperationExampleServices.AddUserInfoTransactions(userInfo);
            return Ok(addUserInfo);
        }

        /// <summary>
        /// 用户信息修改
        /// </summary>
        /// <param name="id">id</param>
        /// <param name="userInfo">userInfo</param>
        /// <returns></returns>
        [HttpPut("{id}")]
        public async Task<ActionResult<UserInfo>> UpdateUserInfo(string id, [FromBody] UserInfoReq userInfo)
        {
            var updateUserInfo = await _userOperationExampleServices.UpdateUserInfo(id, userInfo);
            return Ok(updateUserInfo);
        }

        /// <summary>
        /// 用户信息删除
        /// </summary>
        /// <param name="id">id</param>
        /// <returns></returns>
        [HttpDelete("{id}")]
        public async Task<ActionResult> Delete(string id)
        {
            var deleteUser = await _userOperationExampleServices.Delete(id);
            return Ok(deleteUser);
        }
    }

注册数据库基础操作和工作单元

复制代码
//注册数据库基础操作和工作单元
builder.Services.AddSingleton<IMongoConnection, MongoConnection>();
builder.Services.AddScoped<IMongoContext, MongoContext>();
builder.Services.AddScoped<IUnitOfWork, UnitOfWork>();
builder.Services.AddScoped<IUserRepository, UserRepository>();

注册相关应用服务

复制代码
builder.Services.AddScoped<IUserOperationExampleServices, UserOperationExampleServices>();

Swagger用户管理操作示例展示

添加用户信息

添加成功,返回添加成功的用户信息:

通过用户ID获取对应用户信息

拿刚才添加成功的用户ID,查询用户信息:

获取所有用户信息

用户分页数据获取

查询第1页,显示10条数据:

查询第1页,显示2条数据:

用户信息修改

指定要修改的字段内容,修改HeadPortrait、NickName、Status

参考文章:Update - MongoDB C# docs

修改成功:

用户信息删除

输入需要删除的用户ID,点击Execute删除:

相关推荐
野犬寒鸦1 小时前
从零起步学习JVM || 第一章:类加载器与双亲委派机制模型详解
java·jvm·数据库·后端·学习
czhc11400756631 小时前
通信 28
c#
IvorySQL2 小时前
PostgreSQL 分区表的 ALTER TABLE 语句执行机制解析
数据库·postgresql·开源
·云扬·2 小时前
MySQL 8.0 Redo Log 归档与禁用实战指南
android·数据库·mysql
IT邦德2 小时前
Oracle 26ai DataGuard 搭建(RAC到单机)
数据库·oracle
惊讶的猫3 小时前
redis分片集群
数据库·redis·缓存·分片集群·海量数据存储·高并发写
不爱缺氧i3 小时前
完全卸载MariaDB
数据库·mariadb
纤纡.3 小时前
Linux中SQL 从基础到进阶:五大分类详解与表结构操作(ALTER/DROP)全攻略
linux·数据库·sql
jiunian_cn3 小时前
【Redis】渐进式遍历
数据库·redis·缓存
橙露3 小时前
Spring Boot 核心原理:自动配置机制与自定义 Starter 开发
java·数据库·spring boot