.NET Core MongoDB数据仓储和工作单元模式实操
前言
上一章节我们主要讲解了MongoDB数据仓储和工作单元模式的封装,这一章节主要讲的是MongoDB用户管理相关操作实操。如:获取所有用户信息、获取用户分页数据、通过用户ID获取对应用户信息、添加用户信息、事务添加用户信息、用户信息修改、用户信息删除等实战教程。
MongoDB从入门到实战的相关教程
MongoDB从入门到实战之Docker快速安装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地址:https://github.com/YSGStudyHards/YyFlight.ToDoList
MongoRepository地址:https://github.com/YSGStudyHards/YyFlight.ToDoList/tree/main/Repository/Repository
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.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
参考文章:https://chsakell.gitbook.io/mongodb-csharp-docs/crud-basics/update-documents
修改成功:
用户信息删除
输入需要删除的用户ID,点击Execute删除:
.NET Core MongoDB数据仓储和工作单元模式实操的更多相关文章
- Contoso 大学 - 9 - 实现仓储和工作单元模式
原文 Contoso 大学 - 9 - 实现仓储和工作单元模式 By Tom Dykstra, Tom Dykstra is a Senior Programming Writer on Micros ...
- MVC+EF 理解和实现仓储模式和工作单元模式
MVC+EF 理解和实现仓储模式和工作单元模式 原文:Understanding Repository and Unit of Work Pattern and Implementing Generi ...
- 仓储(Repository)和工作单元模式(UnitOfWork)
仓储和工作单元模式 仓储模式 为什么要用仓储模式 通常不建议在业务逻辑层直接访问数据库.因为这样可能会导致如下结果: 重复的代码 编程错误的可能性更高 业务数据的弱类型 更难集中处理数据,比如缓存 无 ...
- 演练5-8:Contoso大学校园管理系统(实现存储池和工作单元模式)
在上一次的教程中,你已经使用继承来消除在 Student 和 Instructor 实体之间的重复代码.在这个教程中,你将要看到使用存储池和工作单元模式进行增.删.改.查的一些方法.像前面的教程一样, ...
- 知识全聚集 .Net Core 技术突破 | 简单说说工作单元
知识全聚集 .Net Core 技术突破 | 简单说说工作单元 教程 01 | 模块化方案一 02 | 模块化方案二 其他教程预览 分库分表项目实战教程 Git地址: https://github.c ...
- 重新整理 .net core 实践篇—————工作单元模式[二十六]
前言 简单整理一下工作单元模式. 正文 工作单元模式有3个特性,也算是其功能: 使用同一上下文 跟踪实体的状态 保障事务一致性 工作单元模式 主要关注事务,所以重点在事务上. 在共享层的基础建设类库中 ...
- [.NET领域驱动设计实战系列]专题五:网上书店规约模式、工作单元模式的引入以及购物车的实现
一.前言 在前面2篇博文中,我分别介绍了规约模式和工作单元模式,有了前面2篇博文的铺垫之后,下面就具体看看如何把这两种模式引入到之前的网上书店案例里. 二.规约模式的引入 在第三专题我们已经详细介绍了 ...
- [.NET领域驱动设计实战系列]专题四:前期准备之工作单元模式(Unit Of Work)
一.前言 在前一专题中介绍了规约模式的实现,然后在仓储实现中,经常会涉及工作单元模式的实现.然而,在我的网上书店案例中也将引入工作单元模式,所以本专题将详细介绍下该模式,为后面案例的实现做一个铺垫. ...
- .NET应用架构设计—工作单元模式(摆脱过程式代码的重要思想,代替DDD实现轻量级业务)
阅读目录: 1.背景介绍 2.过程式代码的真正困境 3.工作单元模式的简单示例 4.总结 1.背景介绍 一直都在谈论面向对象开发,但是开发企业应用系统时,使用面向对象开发最大的问题就是在于,多个对象之 ...
- 关于工作单元模式——工作单元模式与EF结合的使用
工作单元模式往往和仓储模式一起使用,本篇文章讲到的是工作单元模式和仓储模式一起用来在ef外面包一层,其实EF本身就是工作单元模式和仓储模式使用的经典例子,其中DbContext就是工作单元,而每个Db ...
随机推荐
- 20181224蒋嘉豪-exp3-免杀原理与实现
20181224蒋嘉豪-exp3-免杀原理与实现 目录 20181224蒋嘉豪-exp3-免杀原理与实现 课上知识点总结 1.恶意软件检测机制 2.免杀技术综述 Exp3.1 能够正确使用msf编码器 ...
- jq的用法
选择页面中的元素,得到jQuery实例对象 ID选择器$("#save") 类选择器$(".class") 标签选择器$("div") 复合 ...
- SQL语句底层执行顺序
1. SELECT 语句的完整结构 SQL92语法: SELECT ...,....,(存在聚合函数) FROM ...,...,... WHERE 多表的连接条件 AND 不包含聚合函数的过滤条件 ...
- Markdown基础语法练习
Markdown语法学习 标题 三级标题 四级标题 字体 hello,world! 两端各两个*****号 hello,world! 两端各一个*****号 hello,world! 两端各三个*** ...
- Pytorch Cross Entropy
Entropy Uncetainly measure of surprise higher entropy = less info \[Entropy = -\sum_i P(i)\log P(i) ...
- tuxedo 12c 安装
tuxedo12c 安装命令 静默安装 控制台安装 tuxedo版本介绍 Tuxedo Release Name Tuxedo Release Number Note which contains L ...
- 二、pycharm的安装
1.python安装教程在上一篇已描述,详情查看: 2.安装pycharm 首先从网站下载pycharm:链接为:http://www.jetbrains.com/pycharm/download/# ...
- pandas加速读取数据记录csv大文件处理
def readf(file): t0 = time.time() data=pd.read_csv(file,low_memory=False,encoding='gbk' #,nrows=100 ...
- 学习记录--C++多态性简答+编程题
#include<iostream> #include<string> //双目运算符:运算符作用域两个操作数 //定义一个复数类,重载"+",作为复数类的 ...
- 字符集编码cp936、ANSI、UNICODE、UTF-8、GB2312、GBK、GB18030、DBCS、UCS
一直对字符的各种编码方式懵懵懂懂,什么ANSI.UNICODE.UTF-8.GB2312.GBK.DBCS.UCS--是不是看的很晕,假如您细细的阅读本文你一定可以清晰的理解他们.Let's go! ...