MongoDB结合Flexgrid的简单数据呈现
本示例以常用的:用户,帖子,评论为基础模型,实现了一个简单的MongoDB结合Flexgrid数据呈现的Demo。由于时间所限,功能上仅提供对MongoDB数据的常用查询操作(分页,排序,查询等)。高手请对我这种菜鸟多些包容。
一,准备工作:
MongoDB官方下载:
http://www.mongodb.org/
当前最新版本是2.2.0版本。话说,MongoDB的版本更新是相当的快。
本示例使用的MongoDB C#版驱动下载:
https://github.com/samus/mongodb-csharp
该驱动附源码和示例程序,有兴趣的朋友可以研究一下,对自己的编码能力会有很大的提高。用VS打开Source文件夹,编译后得到程序集,在自己的项目中引用即可。
这是官方邮件提供的 C#版驱动:
https://github.com/mongodb/mongo-csharp-driver/downloads
版本很多,而且基本上都是十多兆的东西,然后,没有然后。
如果你不习惯以命令行的方式对MongoDB进行操作和管理。推荐以下客户端管理工具:
1,MongoVUE。这应该是目前应用最广的了。
下载地址:http://www.mongovue.com/
2,博客园高手自己开发的MongoDB管理工具:
http://www.cnblogs.com/texteditor/archive/2012/03/31/2427195.html
试用了一下,也是相当不错的!
虽然上述管理工具能够以图形化的方式与MongoDB交互,但强烈建议你运行mongo.exe客户端,以命令行的方式对MongoDB进行操作和管理,这会让你对MongoDB有更加直观而深刻的体会。另外,Windows8依然内置了DOS。
这里有MongoDB的常用命令:
http://blog.csdn.net/shirdrn/article/details/7105539
这是Flexgrid的官方网站:
http://flexigrid.info/
页面顶部有一个硕大的红色Download按钮。
TestDriven.net,必不可少的开发和测试工具。本示例需要用它向MongoDB中初始化测试数据。下载地址:
二,项目结构:
麻雀虽小,五脏俱全。整个项目结构是一个最原始的三层。直接上图:
三,技术细节:
1,MongoDB数据库操作。
ADO.NET虽然很强大,但我们通常需要自己动手写一个SqlHelper。MongoDB也一样,我们仍有必要在驱动的基础上对常用的数据操作进行封装。下面贴出本鸟写的MongoDB数据库操作类。大多数方法都与数据查询相关。贴出主要代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 | using System; using System.Collections.Generic; using System.Linq; using System.Configuration; using MongoDB; using MongoDB.Linq; using Mcmurphy.Commons.Enumerations; namespace Mcmurphy.DAL { public class MongoDBHelper { #region 基本信息 private static readonly string ConnectionString; private static readonly string DatabaseName; /// <summary> /// 当前Mongo引用 /// </summary> private static Mongo mongo; /// <summary> /// 初始化数据库配置 /// </summary> static MongoDBHelper() { ConnectionString = ConfigurationManager.AppSettings[ "connString" ]; DatabaseName = ConfigurationManager.AppSettings[ "currentDB" ]; } /// <summary> /// 当前Mongo对象 /// </summary> private static Mongo CurrentMongo { get { return new Mongo(ConnectionString); } } /// <summary> /// 当前操作集合 /// </summary> private static IMongoCollection<T> GetCollection<T>() where T: class { try { mongo = CurrentMongo; mongo.Connect(); IMongoDatabase db = GetCurrentDataBase(); IMongoCollection<T> collection = db.GetCollection<T>(); return collection; } catch (Exception ex) { throw ex; } } /// <summary> /// 获取当前Mongo数据库对象 /// </summary> /// <returns>当前Mongo数据库对象</returns> private static IMongoDatabase GetCurrentDataBase() { return mongo.GetDatabase(DatabaseName); } #endregion #region 数据查询 /// <summary> /// 获取排序规则 /// </summary> private static IndexOrder GetIndexOrder(DataOrder order) { IndexOrder @ orderby = order == DataOrder.Ascending ? IndexOrder.Ascending : IndexOrder.Descending; return orderby ; } /// <summary> /// 根据条件进行查询,并进行分页 /// </summary> /// <typeparam name="T">类型参数</typeparam> /// <param name="selector">条件Lamda表达式</param> /// <param name="pageIndex">当前页索引</param> /// <param name="pageSize">分页大小</param> /// <returns>结果集</returns> public static IEnumerable<T> GetBySearch<T>(System.Linq.Expressions.Expression<Func<T, bool >> selector, int pageIndex, int pageSize) where T : class { try { var currentCollection = GetCollection<T>(); return currentCollection.Find<T>(selector).Skip((pageIndex - 1) * pageSize).Limit(pageSize).Documents.ToList(); } catch (Exception ex) { throw ex; } finally { mongo.Disconnect(); mongo.Dispose(); } } /// <summary> /// 根据条件进行查询,并进行分页和排序 /// </summary> /// <typeparam name="T">类型参数</typeparam> /// <param name="selector">条件Lamda表达式</param> /// <param name="pageIndex">当前页索引</param> /// <param name="pageSize">分页大小</param> /// <param name="order">排序规则</param> /// <param name="orderField">排序字段</param> /// <returns>结果集</returns> public static IEnumerable<T> GetBySearch<T>(System.Linq.Expressions.Expression<Func<T, bool >> selector, int pageIndex, int pageSize, DataOrder order, string orderField) where T : class { try { IndexOrder orderby = GetIndexOrder(order); var currentCollection = GetCollection<T>(); return currentCollection.Find<T>(selector).Sort(orderField, orderby ).Skip((pageIndex - 1) * pageSize).Limit(pageSize).Documents.ToList(); } catch (Exception ex) { throw ex; } finally { mongo.Disconnect(); mongo.Dispose(); } } /// <summary> /// 根据条件查询一个对象 /// </summary> /// <typeparam name="T">类型参数</typeparam> /// <param name="selector">查询条件Lamda表达式</param> /// <returns>查询对象</returns> public static T GetOneBySearch<T>(System.Linq.Expressions.Expression<Func<T, bool >> selector) where T : class { try { var currentCollection = GetCollection<T>(); return currentCollection.FindOne<T>(selector); } catch (Exception ex) { throw ex; } finally { mongo.Disconnect(); mongo.Dispose(); } } /// <summary> /// 根据查询条件获取总记录数 /// </summary> /// <typeparam name="T">类型参数</typeparam> /// <param name="selector">查询条件</param> /// <returns>记录数</returns> public static long GetTotalCount<T>(System.Linq.Expressions.Expression<Func<T, bool >> selector) where T : class { try { var currentCollection = GetCollection<T>(); return currentCollection.Count(selector); } catch (Exception ex) { throw ex; } finally { mongo.Disconnect(); mongo.Dispose(); } } /// <summary> /// 获取总记录数 /// </summary> /// <typeparam name="T">类型参数</typeparam> /// <returns>记录数</returns> public static long GetTotalCount<T>() where T : class { try { var currentCollection = GetCollection<T>(); return currentCollection.Count(); } catch (Exception ex) { throw ex; } finally { mongo.Disconnect(); mongo.Dispose(); } } #endregion #region 数据插入 /// <summary> /// 数据插入 /// </summary> /// <typeparam name="T">类型参数</typeparam> /// <param name="t">要插入的数据对象</param> public static void Insert<T>(T t) where T : class { try { var currentCollection = GetCollection<T>(); currentCollection.Insert(t); } catch (Exception ex) { throw ex; } finally { mongo.Disconnect(); mongo.Dispose(); } } #endregion #region 数据更新 /// <summary> /// 根据查询条件更新数据 /// </summary> /// <typeparam name="T">类型参数</typeparam> /// <param name="t">待更新的对象</param> /// <param name="selector">更新的条件Lamda表达式</param> public static void Update<T>(T t, System.Linq.Expressions.Expression<Func<T, bool >> selector) where T : class { try { var currentCollection = GetCollection<T>(); currentCollection.Update<T>(t,selector); } catch (Exception ex) { throw ex; } finally { mongo.Disconnect(); mongo.Dispose(); } } /// <summary> /// 更新/插入数据(id是否存在) /// </summary> /// <typeparam name="T">类型参数</typeparam> /// <param name="t">待更新的对象</param> public static void Update<T>(T t) where T : class { try { var currentCollection = GetCollection<T>(); //inserts of updates depends on whether id exists currentCollection.Save(t); } catch (Exception ex) { throw ex; } finally { mongo.Disconnect(); mongo.Dispose(); } } #endregion #region 数据删除 /// <summary> /// 数据删除 /// </summary> /// <typeparam name="T">类型参数</typeparam> /// <param name="selector">查询的条件Lamda表达式</param> public static void Delete<T>(System.Linq.Expressions.Expression<Func<T, bool >> selector) where T : class { try { var currentCollection = GetCollection<T>(); currentCollection.Remove<T>(selector); } catch (Exception ex) { throw ex; } finally { mongo.Disconnect(); mongo.Dispose(); } } #endregion } } |
初次调用的时候,会读取在站点项目下Web.Config文件中配置的数据库服务器地址以及数据库名称。
2,Flexgrid加载的数据格式。
在官网上徘徊了很久也没有找到Flexgrid要求的数据格式说明。还好有Firebug,但遗憾的是官方示例采用的是XML格式。如下:
<rows> <page>1</page> <total>234</total> <row id='AD'> <cell><![CDATA[AD]]></cell> ... </row> ... </rows>
上述XML存在一个问题,就是具体的列并没有id标识。也就是说,在配置Flexgrid的时候,你必须了解服务器返回的数据字段的顺序。否则就会出现“标题列显示回复数”的情况。在数据格式为Json的时候,也会出现同样的状况。理想情况下,官方应该给出的XML数据格式如下:
<rows> <page>1</page> <total>234</total> <row id='AD'> <cell id='name'><![CDATA[AD]]></cell> ... </row> ... </rows>
对于本示例采用的Json,经测试,完整的数据格式如下:
{ "page":当前页, "total":总记录数, "rows":[ { "id":当前行编号, "cell":{ "username":"mcmurphy", "password":"mcmurphy", ... } } ... ] }
Flexgrid官方文档的欠缺和一个无意的疏忽,相信一定误导了不少人,也导致本鸟走了不少弯路。
对于服务器向客户端输出Json,使用了Newtonsoft.Json这个第三方组件,有兴趣的朋友可以百度一下。
当然,在System.Web.Script.Serialization命名空间下,有一个JavaScriptSerializer类,也可以对Json进行序列化与反序列化的操作。
3,LINQ的动态组合查询。
LINQ虽然给我们提供了很多方便,但在多条件组合查询方面,显然没有传统的拼接SQL来得直观和爽快。网上流传的很多解决方案,代码一坨一坨的,看了都头痛,而且基本都是抄来抄去。后来找到杨过前辈的一篇,比较有参考价值:
http://www.cnblogs.com/yjmyzz/archive/2008/03/25/1122135.html
主要借助了老外写的一个扩展表达式,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | using System; using System.Linq; using System.Linq.Expressions; namespace Mcmurphy.DAL { /// <summary> /// 老外写的,非常厉害 /// </summary> public static class PredicateExtensions { public static Expression<Func<T, bool >> True<T>() { return f => true ; } public static Expression<Func<T, bool >> False<T>() { return f => false ; } public static Expression<Func<T, bool >> Or<T>( this Expression<Func<T, bool >> expression1, Expression<Func<T, bool >> expression2) { var invokedExpression = Expression.Invoke(expression2, expression1.Parameters.Cast<Expression>()); return Expression.Lambda<Func<T, bool >>(Expression.Or(expression1.Body, invokedExpression), expression1.Parameters); } public static Expression<Func<T, bool >> And<T>( this Expression<Func<T, bool >> expression1, Expression<Func<T, bool >> expression2) { var invokedExpression = Expression.Invoke(expression2, expression1.Parameters.Cast<Expression>()); return Expression.Lambda<Func<T, bool >>(Expression.And(expression1.Body, invokedExpression), expression1.Parameters); } } } |
上述代码主要是进行逻辑运算的四个方法,代码很短,但我们不得不佩服老外的功力。
关于老外的这个扩展表达式,还有前辈写过一篇讲解:
http://www.cnblogs.com/whitewolf/archive/2010/08/02/1790390.html
四,最终运行
有图有真相:
本文主要是做一个梳理和记录。示例中用到的很多技术都比较简单,当然也有很多不足之处,这对一个菜鸟来说在所难免。希望路过的高手给予最严厉的批评和指正。放心,你只要不能直接干掉我,都只会让我更加坚强。 (^o^)
下面流出源码种子(运行前请读一下:读我.txt):源码种子
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· [AI/GPT/综述] AI Agent的设计模式综述