RavenDB介绍
RavenDB是一个基于.NET开发的NoSQL数据库。下面是官方介绍的一个简单翻译:
RavenDB is a transactional, open-source Document Database written in .NET, offering a flexible data model designed to address requirements coming from real-world systems.
RavenDB allows you to build high-performance, low-latency applications quickly and efficiently.
RavenDB是一个用.NET编写的事务性开源文档数据库,提供灵活的数据模型,设计用于解决来自真实世界系统的需求。
RavenDB允许你快速而高效地构建高性能、低延迟的应用程序。
更多介绍可以浏览官方网站的介绍: 场景介绍
由于NoSQL一般是用于Web场景,比如Web应用程序(尤其MVC Web应用程序),或者Web服务(包括REST服务等)。最近,香港服务器租用,需要实现一个简单的数据编辑工具,不过由于某些原因,这个工具必须和一个桌面的Windows Forms应用程序集成在一起,且也要满足多个用户同时操作数据的需求。对于这种标准的C/S模式的应用,能否使用RavenDB这样的NoSQL来作为Server端的数据库呢?
答案当然是可以的。毕竟RavenDB本身就支持两种运行模式:嵌入模式(Embedded)和服务器模式(Server)。对于C/S的应用,很自然就是把RavenDB部署在一个服务器上,运行于Server模式,然后在客户端通过.NET Client API来访问。
遇到问题在这个C/S应用程序中使用RavenDB的过程中,遇到的最大的问题,还是RavenDB本身的一些特性所带来的限制,分别为:
针对以上的限制,并结合我这个C/S小工具的一些特点,使用了如下解决方式:
代码见:https://github.com/heavenwing/redmoon/blob/master/RavenDBDataSource.cs
这个类提供了一个构造器public RavenDBDataSource(IDocumentStore store, BindingNavigator bn, BindingSource bs),可以接受IDocumentStore 、BindingNavigator 和BindingSource 作为参数。其中会对bn进行一些初始化处理。
提供了一个重载的Load方法,可以无参数,或者接受Func<IRavenQueryable<T>, IRavenQueryable<T>> criteria, string indexName = ""两个参数。criteria用来对查询进行构造,indexName顾名思义,在进行Search操作的时候就需要传入预先定义的索引的名称。在Load方法中,会对调用代码构造好的查询进行执行,根据PageSize的设置进行分页查询,把查询结果赋值给BindingSource来提示和BindingSource绑定的控件(如DataGridView)进行刷新。在进行分页查询的同时,也会更新当前的页码。
其中BindingNavigator 对象的PositionItem的TextChanged事件处理,会触发Load事件。为了避免频率过高的执行,我使用了一个自定义的事件延迟器(见:https://github.com/heavenwing/redmoon/blob/master/DelayEvent.cs),当然也可以使用RX来进行延迟。
具体用法就很简单:实例化一个用于具体实体类的RavenDBDataSource,然后调用Load方法,在Load方法中构造查询。如:
private void LoadProcessData() { if (_dsProcess == null) _dsProcess = new RavenDBDataSource<ProcessEntity>(_store, bnProcess, bsProcess); var txt = tstbSearchForProcess.Text.ToLower(); if (string.IsNullOrEmpty(txt)) { if (tscbSource.SelectedIndex == 0) { if (tscbRelatedCount.SelectedIndex < 5) _dsProcess.Load(query => query .Where(o => o.RelatedCount == tscbRelatedCount.SelectedIndex) .OrderBy(o => o.ProductName)); else _dsProcess.Load(query => query .Where(o => o.RelatedCount >= 5) .OrderBy(o => o.ProductName)); } else { if (tscbRelatedCount.SelectedIndex < 5) _dsProcess.Load(query => query .Where(o => o.Source == tscbSource.Text && o.RelatedCount==tscbRelatedCount.SelectedIndex) .OrderBy(o => o.ProductName)); else { _dsProcess.Load(query => query .Where(o => o.Source == tscbSource.Text && o.RelatedCount >= 5) .OrderBy(o => o.ProductName)); } } } else { _dsProcess.Load(query => query .Search(o => o.ProductName, txt) .OrderBy(o => o.ProductName), index1Name ); } }上述代码中,可以同时对多个属性进行过滤(Where),也可通过设定索引名称(index1Name)对一个或多个属性进行搜索(Search)。