- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
SqlSugar的开发框架本身主要是基于常规关系型数据库设计的框架,支持多种数据库类型的接入,如SqlServer、MySQL、Oracle、PostgreSQL、SQLite等数据库,非关系型数据库的MongoDB数据库也可以作为扩展整合到开发框架里面,通过基类的继承关系很好的封装了相关的基础操作功能,极大的减少相关处理MongoDB的代码,并提供很好的开发效率。本篇随笔介绍如何在SqlSugar的开发框架整合MongoDB数据库的开发.
MongoDB是一款由C++编写的高性能、开源、无模式的常用非关系型数据库产品,是非关系数据库当中功能最丰富、最像关系数据库的数据库。它扩展了关系型数据库的众多功能,例如:辅助索引、范围查询、排序等。 。
MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似Json的Bson格式,因此可以存储比较复杂的数据类型。 MongoDB 最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。并且MongoDB-4.2版本开始已经支持分布式事务功能.
MongoDB数据库有几个简单的概念需要了解一下.
1)MongoDB中的 database 有着和我们熟知的"数据库"一样的概念 (对 Oracle 来说就是 schema)。一个 MongoDB 实例中,可以有零个或多个数据库,每个都作为一个高等容器,用于存储数据.
2)数据库中可以有零个或多个 collections (集合)。集合和传统意义上的 table 基本一致,可以简单的把两者看成是一样的东西.
3)集合是由零个或多个 documents (文档)组成。同样,一个文档可以看成是一 row .
4)文档是由零个或多个 fields (字段)组成。,对应的就是关系数据库的 columns .
5) Indexes (索引)在 MongoDB 中扮演着和它们在 RDBMS 中一样的角色,都是为了提高查询的效率.
6) Cursors (游标)和上面的五个概念都不一样,但是它非常重要,并且经常被忽视,其中最重要的你要理解的一点是,游标是当你问 MongoDB 拿数据的时候,它会给你返回一个结果集的指针而不是真正的数据,这个指针我们叫它游标,我们可以拿游标做我们想做的任何事情,比如说计数或者跨行之类的,而无需把真正的数据拖下来,在真正的数据上操作.
它们的对比关系图如下所示.
数据在Mongodb里面都是以Json格式方式进行存储的,如下所示是其中的一个记录内容.
BSON格式 。
Bson是一种类Json的一种 二进制 形式的存储格式,简称Binary Json,它和Json一样,支持内嵌的文档对象和数组对象,但是Bson有Json没有的一些数据类型,如Date和BinData类型.
Bson可以做为网络数据交换的一种存储形式,这个有点类似于Google的Protocol Buffer ,但是Bson是一种schema-less的存储形式,它的优点是灵活性高,但它的缺点是空间利用率不是很理想,Bson有三个特点:轻量性、可遍历性、高效性, 。
{“hello":"world"} 这是一个Bson的例子,其中"hello"是key name,它一般是cstring类型,字节表示是cstring::= (byte*) "/x00" ,其中*表示零个或多个byte字节,/x00表示结束符;后面的"world"是value值,它的类型一般是string,double,array,binarydata等类型.
MongDB数据库本身支持多种开发语言的驱动,MongoDB有官方的驱动如下:
我们框架基于C#开发,使用的时候,安装MongoDB的C#的驱动 MongoDB.Driver 即可.
在MongoDB数据库的集合里面,都要求文档有一个_id字段,这个是强制性的,而且这个字段的存储类型为ObjectId类型,这个值考虑了分布式的因素,综合了机器码,进程,时间戳等等方面的内容,它的构造如下所示.
ObjectId是一个12字节的 BSON 类型字符串。按照字节顺序,依次代表:
实体基类一般包含了一个属性Id,这个是一个字符串型的对象(也可以使用ObjectId类型,但是为了方便,我们使用字符型,并声明为ObjectId类型即可),由于我们声明了该属性对象为ObjectId类型,那么我们就可以在C#代码里面使用字符串的ID类型了.
。
以前介绍过,针对常规关系型数据库的开发,在SqlSugar开发框架上,我们设计一些基类,以便重用相关的逻辑代码,通过泛型的约束,可以提供强类型的数据接口,非常方便.
其中MyCrudService里面封装了很多CRUD以及常用的处理方法。类似的处理方式,我们专门为MongoDB数据库的访问操作,设计了一个功能强大的基类即可.
在数据库表的实体对应关系上,我们依旧遵循则相应的设计规则,基类实体采用IEntity<string>的接口类型,因此他们具有一个字符串的Id类型。其他业务对象继承该基类对象即可.
/// <summary> /// 基于MongoDB的实体类基类 /// </summary> public class BaseMongoEntity : Entity< string > { [BsonId] [BsonRepresentation(BsonType.ObjectId)] public override string Id { get ; set ; } }
相应的,我们根据常规数据库的基类接口名称,在处理MongoDB数据库的操作接口的时候,名称保持一致性.
其中TEntity为强类型实体类型,而TGetListInput 是定义的一个分页接口。定义的基类接口代码如下所示.
其中接口对象 CurrentApiUser是我们用户上下文的信息,包含一些驻留在ClainPrincipal中的信息,用于记录访问接口的用户信息的.
其他接口定义类似的处理即可.
基类接口的实现类,就是我们需要设计的MongoDB数据库操作类了,初始化类的代码如下所示.
/// <summary> /// MongoDB基础仓储实现 /// </summary> /// <typeparam name="TEntity"></typeparam> public abstract class BaseMongoService <TEntity, TGetListInput> : IBaseMongoService <TEntity, TGetListInput> where TEntity : class , IEntity< string >, new () where TGetListInput : IPagedAndSortedResultRequest { protected readonly IMongoDBContext mongoContext = NullMongoDBContext.Instance ; // 空实现 protected IMongoCollection<TEntity> collection ; // 强类型对象集合 protected IMongoCollection<BsonDocument> bsonCollection ; // 弱类型集合BsonDocument集合 /// <summary> /// 当前Api用户信息 /// </summary> public IApiUserSession CurrentApiUser { get ; set ; } = NullApiUserSession.Instance; // 空实现 /// <summary> /// 构造函数 /// </summary> protected BaseMongoService() { // 如果SerivcePovider已经设置值,则获得注入的接口对象 if (ServiceLocator.SerivcePovider != null ) { CurrentApiUser = ServiceLocator.GetService<IApiUserSession> (); mongoContext = ServiceLocator.GetService<IMongoDBContext> (); collection = mongoContext.GetCollection<TEntity>( typeof (TEntity).Name); // 强类型对象集合 bsonCollection = mongoContext.GetCollection<BsonDocument>( typeof (TEntity).Name); // 弱类型集合BsonDocument集合 } } /// <summary> /// 获取所有记录 /// </summary> /// <returns></returns> public virtual async Task<ListResultDto<TEntity>> GetAllAsync() { var all = await collection.FindAsync(Builders<TEntity> .Filter.Empty); var list = await all.ToListAsync(); return new ListResultDto<TEntity> () { Items = list }; }
我们通过构建对应的强类型Collection和弱类型Collection,来操作实体类和BsonDocument的相关操作的。其中的上下文对象,参考随笔《 NoSQL – MongoDB Repository Implementation in .NET Core with Unit Testing example 》进行的处理.
/// <summary> /// MongoDB 上下文对象 /// </summary> public class MongoDBContext : IMongoDBContext { private IMongoDatabase _db { get ; set ; } private MongoClient _mongoClient { get ; set ; } public IClientSessionHandle Session { get ; set ; } public MongoDBContext( IOptions<Mongosettings> configuration) { _mongoClient = new MongoClient(configuration.Value.Connection); _db = _mongoClient.GetDatabase(configuration.Value.DatabaseName); } /// <summary> /// 获取强类型集合对象 /// </summary> /// <typeparam name="T"> 对象类型 </typeparam> /// <param name="name"></param> /// <returns></returns> public IMongoCollection<T> GetCollection<T>( string name) where T : class , new () { return _db.GetCollection<T> (name); } } public interface IMongoDBContext { IMongoCollection <T> GetCollection<T>( string name) where T : class , new (); }
通过IOptions 方式我们注入对应的MongoDB数据库配置信息,在appsettings.json中添加根节点内容.
" MongoSettings " : { "Connection": "mongodb://localhost:27017/", // MongoDB连接字符串 "DatabaseName": "iqidi" // MongoDB数据库名称 },
我们在启动Web API的时候,在Program.cs 代码中配置好就可以了.
// MongoDB配置 builder.Services.Configure<Mongosettings>(builder.Configuration.GetSection("MongoSettings"));
默认初始化的IMongoDBContext是一个空接口,我们可以在Web API启动的时候,指定一个具体的实现就可以了 。
// 添加IMongoContext实现类 builder.Services.AddSingleton<IMongoDBContext, MongoDBContext >();
对于基类接口,分页查询获取对应列表数据,是常规的处理方式,默认需要排序、分页,返回对应的数据结构,如下代码所示.
// / <summary> // / 根据条件获取列表 // / </summary> // / <param name="input">分页查询条件</param> // / <returns></returns> public virtual async Task<PagedResultDto<TEntity>> GetListAsync(TGetListInput input) { var query = CreateFilteredQueryAsync(input); var totalCount = await query.CountAsync(); // 排序处理 query = ApplySorting(query, input); // 分页处理 query = ApplyPaging(query, input); // 获取列表 var list = await query.ToListAsync(); return new PagedResultDto <TEntity> ( totalCount, list ); }
其中 PagedResultDto 是我们SqlSugar开发框架参照ABP框架定义一个数据结构,包含一个TotalCount数量和一个Items的对象集合。而其中 CreateFilteredQueryAsync 是定义的一个可供业务子类重写的函数,用来处理具体的查询条件。在基类BaseMongoService中只是提供一个默认的可查询对象.
// / <summary> // / 留给子类实现过滤条件的处理 // / </summary> // / <returns></returns> protected virtual IMongoQueryable<TEntity> CreateFilteredQueryAsync (TGetListInput input) { return collection.AsQueryable(); }
例如,对于一个具体的业务对象操作类,CustomerService的定义如下所示,并且具体化查询的条件处理,如下代码所示.
namespace SugarProject.Core.MongoDB { // / <summary> // / 基于MongoDB数据库的应用层服务接口实现 // / </summary> public class CustomerService : BaseMongoService<CustomerInfo, CustomerPagedDto> , ICustomerService { // / <summary> // / 构造函数 // / </summary> public CustomerService() { } // / <summary> // / 自定义条件处理 // / </summary> // / <param name="input">查询条件Dto</param> // / <returns></returns> protected override IMongoQueryable<CustomerInfo> CreateFilteredQueryAsync (CustomerPagedDto input) { var query = base.CreateFilteredQueryAsync(input); query = query .Where(t => !input.ExcludeId.IsNullOrWhiteSpace() && t.Id != input.ExcludeId) // 不包含排除ID .Where(t=> !input.Name.IsNullOrWhiteSpace() && t.Name.Contains(input.Name)) // 如需要精确匹配则用Equals // 年龄区间查询 .Where(t=> input.AgeStart.HasValue && t.Age >= input.AgeStart.Value) .Where(t => input.AgeEnd.HasValue && t.Age <= input.AgeEnd.Value) // 创建日期区间查询 .Where(t => input.CreateTimeStart.HasValue && t.CreateTime >= input.CreateTimeStart.Value) .Where(t => input.CreateTimeEnd.HasValue && t.CreateTime <= input.CreateTimeEnd.Value) ; return query; }
这个处理方式类似于常规关系型数据库的处理方式,就是对条件的判断处理。而具体的业务对象模型,和常规框架的实体类很类似.
/// <summary> /// 客户信息 /// 继承自BaseMongoEntity,拥有Id主键属性 /// </summary> public class CustomerInfo : BaseMongoEntity { /// <summary> /// 默认构造函数(需要初始化属性的在此处理) /// </summary> public CustomerInfo() { this .CreateTime = System.DateTime.Now; } #region Property Members /// <summary> /// 姓名 /// </summary> public virtual string Name { get ; set ; } /// <summary> /// 年龄 /// </summary> public virtual int Age { get ; set ; } /// <summary> /// 创建人 /// </summary> public virtual string Creator { get ; set ; } /// <summary> /// 创建时间 /// </summary> public virtual DateTime CreateTime { get ; set ; } #endregion }
对于插入和更新操作等常规操作,我们调用普通的Collection操作处理就可以了 。
/// <summary> /// 创建对象 /// </summary> /// <param name="input"> 实体对象 </param> /// <returns></returns> public virtual async Task InsertAsync(TEntity input) { SetObjectIdIfEmpty(input); // 如果Id为空,设置为ObjectId的值 await collection.InsertOneAsync(input); } /// <summary> /// 更新记录 /// </summary> public virtual async Task< bool > UpdateAsync(TEntity input) { SetObjectIdIfEmpty(input); // 如果Id为空,设置为ObjectId的值 // await _dbSet.ReplaceOneAsync(Builders<TEntity>.Filter.Eq("_id", input.Id), input); // 要修改的字段 var list = new List<UpdateDefinition<TEntity>> (); foreach ( var item in input.GetType().GetProperties()) { if (item.Name.ToLower() == " id " ) continue ; list.Add(Builders <TEntity> .Update.Set(item.Name, item.GetValue(input))); } var updatefilter = Builders<TEntity> .Update.Combine(list); var update = await collection.UpdateOneAsync(Builders<TEntity>.Filter.Eq( " _id " , input.Id), updatefilter); var result = update != null && update.ModifiedCount > 0 ; return result; }
更新操作,有一种整个替换更新,还有一个是部分更新,它们两者是有区别的。如果对于部分字段的更新,那么操作如下所示 ,主要是利用UpdateDefinition对象来指定需要更新那些字段属性及值等信息.
/// <summary> /// 封装处理更新的操作(部分字段更新) /// </summary> /// <example> /// var update = Builders <UserInfo> .Update.Set(s => s.Name, newName); /// </example> public virtual async Task< bool > UpdateAsync( string id, UpdateDefinition<TEntity> update) { var result = await collection.UpdateOneAsync(s => s.Id == id, update, new UpdateOptions() { IsUpsert = true }); return result != null && result.ModifiedCount > 0 ; }
根据MongoDB数据库的特性,我们尽量细化对数据库操作的基类接口,定义所需的接口函数即可.
对于Web API的控制器设计,我们在之前的随笔也有介绍,为常规授权处理的BaseApiController,为常规业务CRUD等接口处理的BusinessController,如下所示.
。
其中ControllerBase是.net core Web API中的标准控制器基类,我们由此派生一个LoginController用于登录授权,而BaseApiController则处理常规接口用户身份信息,而BusinessController则是对标准的增删改查等基础接口进行的封装,我们实际开发的时候,只需要开发编写类似CustomerController基类即可.
而对于 MongoDB的Web API控制器,我们为了方便开发,也设计了同类型的Web API 控制器基类.
其中MongoBaseController基类具有常规的CRUD的接口定义处理,只要继承它就可以了,而如果只是继承BaseApiController这需要自定义控制器接口的方法.
最后我们启动Swagger进行测试对应的接口即可,实际还可以整合在UI中进行测试处理。我们安装MongoDB数据库的管理工具后,可以在 MongoDBCompass 中进行查询对应数据库的数据.
/// <summary> /// 客户信息的控制器对象(基于MongoDB),基于BaseApiController,需要自定义接口处理 /// </summary> [ApiController] [Route( " api/MongoCustomer " )] public class MongoCustomerController : BaseApiController { private ICustomerService _service; /// <summary> /// 构造函数,并注入基础接口对象 /// </summary> /// <param name="service"></param> public MongoCustomerController(ICustomerService service) { this ._service = service; } /// <summary> /// 获取所有记录 /// </summary> [HttpGet] [Route( " all " )] public virtual async Task<ListResultDto<CustomerInfo>> GetAllAsync() { // 检查用户是否有权限,否则抛出MyDenyAccessException异常 base .CheckAuthorized(AuthorizeKey.ListKey); return await _service.GetAllAsync(); }
而如果继承自MongoBaseController ,那么就会具有基类MongoBaseController 公开的所有控制器方法。 。
/// <summary> /// 客户信息的控制器对象(基于MongoDB),基于MongoBaseController,具有常规CRUD操作接口 /// </summary> [ApiController] [Route( " api/MongoCustomer2 " )] public class MongoCustomer2Controller : MongoBaseController<CustomerInfo, CustomerPagedDto> { /// <summary> /// 构造函数,并注入基础接口对象 /// </summary> /// <param name="service"></param> public MongoCustomer2Controller(ICustomerService service) : base (service) { } }
。
早几年前曾经也介绍过该数据库的相关使用,随笔如下所示,有需要也可以了解下.
最后此篇关于基于SqlSugar的开发框架循序渐进介绍(27)--基于MongoDB的数据库操作整合的文章就讲到这里了,如果你想了解更多关于基于SqlSugar的开发框架循序渐进介绍(27)--基于MongoDB的数据库操作整合的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我需要开发一个简单的网站,我通常使用 bootstrap CSS 框架,但是我想使用 Gumbyn,它允许我使用 16 列而不是 12 列。 我想知道是否: 我可以轻松地改变绿色吗? 如何使用固定布局
这个问题在这里已经有了答案: 关闭 13 年前。 与直接编写 PHP 代码相比,使用 PHP 框架有哪些优点/缺点?
我开发了一个 Spring/JPA 应用程序:服务、存储库和域层即将完成。 唯一缺少的层是网络层。我正在考虑将 Playframework 2.0 用于 Web 层,但我不确定是否可以在我的 Play
我现有的 struts Web 应用程序具有单点登录功能。然后我将使用 spring 框架创建一个不同的 Web 应用程序。然后想要使用从 struts 应用程序登录的用户来链接新的 spring 应
我首先使用Spark框架和ORMLite处理网页上表单提交的数据,在提交中文字符时看到了unicode问题。我首先想到问题可能是由于ORMLite,因为我的MySQL数据库的字符集已设置为使用utf8
我有一个使用 .Net 4.5 功能的模块,我们的应用程序也适用于 XP 用户。所以我正在考虑将这个 .net 4.5 依赖模块移动到单独的项目中。我怎样才能有一个解决方案,其中有两个项目针对不同的版
我知道这是一个非常笼统的问题,但我想我并不是真的在寻找明确的答案。作为 PHP 框架的新手,我很难理解它。 Javascript 框架,尤其是带有 UI 扩展的框架,似乎通过将 JS 代码与设计分开来
我需要收集一些关于现有 ORM 解决方案的信息。 请随意编写任何编程语言。 你能谈谈你用过的最好的 ORM 框架吗?为什么它比其他的更好? 最佳答案 我使用了 NHibernate 和 Entity
除了 Apple 的 SDK 之外,还有什么强大的 iPhone 框架可供开始开发?有没有可以加快开发时间的方法? 最佳答案 此类框架最大的是Three20 。 Facebook 和许多其他公司都使用
有人可以启发我使用 NodeJS 的 Web 框架吗?我最近开始从免费代码营学习express js,虽然一切进展顺利,但我对express到底是什么感到困惑。是全栈框架吗?纯粹是为了后端吗?我发现您
您可以推荐哪种 Ajax 框架/工具包来构建使用 struts 的 Web 应用程序的 GUI? 最佳答案 我会说你的 AJAX/javascript 库选择应该较少取决于你的后端是如何实现的,而更多
我有生成以下错误的 python 代码: objc[36554]: Class TKApplication is implemented in both /Library/Frameworks/Tk.
首先,很抱歉,如果我问的问题很明显,因为我没有编程背景,那我去吧: 我想运行一系列测试场景并在背景部分声明了几个变量(我打印它们以仔细检查它们是否已正确声明),第一个是整数,另外两个字符串为你可以看到
在我们承担的一个项目中,我们正在寻找一个视频捕获和录制库。我们的基础工作(基于 google 搜索)表明 vlc (libvlc)、ffmpeg (libavcodec) 和 gstreamer 是三
我试过没有运气的情况下寻找某种功能来杀死/中断Play中的正常工作!框架。 我想念什么吗?还是玩了!实际没有添加此功能? 最佳答案 Java stop类中没有像Thread方法那样的东西,由于种种原因
我们希望在我们的系统中保留所有重大事件的记录。例如,在数据库可能存储当前用户状态的地方,事件日志应记录对该状态的所有更改以及更改发生的时间。 事件记录工具应该尽可能接近于事件引发器的零开销,应该容纳结
那里有 ActionScript 2.0/3.0 的测试框架列表吗? 最佳答案 2010-05-18 更新 由于这篇文章有点旧,而且我刚刚收到了赞成票,因此可能值得提供一些更新的信息,这样人们就不会追
我有一个巨大的 numpy 数组列表(一维),它们是不同事件的时间序列。每个点都有一个标签,我想根据其标签对 numpy 数组进行窗口化。我的标签是 0、1 和 2。每个窗口都有一个固定的大小 M。
我是 Play 的新手!并编写了我的第一个应用程序。这个应用程序有一组它依赖的 URL,从 XML 响应中提取数据并返回有效的 URL。 此应用程序需要在不同的环境(Dev、Staging 和 Pro
关闭。这个问题不满足Stack Overflow guidelines .它目前不接受答案。 想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。 4年前关闭。 Improve thi
我是一名优秀的程序员,十分优秀!