说到数据持久化,.net下数据持久化框架主要有以下几种:
1.NHibernate 2.NBear 3.Castle ActiveRecord 4.iBATIS.NET 5.DAAB
这里我只谈下的使用感受和经验分享,首先,简短介绍下是什么样个东东:NBear是一个基于.Net 2.0、C#2.0开放全部源代码的的软件开发框架类库。NBear的设计目标是尽最大努力减少开发人员的工作量,最大程度提升开发效率,同时兼顾性能及可伸缩性。其主要功能有:数据持久化,IOC等;它是博客园首个开源团队开发的框架(所以,想了解其更多信息和获得不同版本的源码,直接在博客园里搜索很容易找到)。
接触NBear算是一个比较偶然的机会——因项目开发中想避免因为数据库表或字段名更改后需要重新生成代码,及修改数据处理层中SQL语句(非代码生成器生成的)或因有些SQL忘记修改导致程序错误的问题,于是,尝试用一些方法替代这种手写的SQL(改变现有的数据持久化方式),网上搜索了几个数据持久化框架,分析对比试用后,感觉算是易用和扩展性都不错,且性能也相对突出的一个.net数据持久化框架(其中Nbear的一个版本NBearLite,是读写性能都比较高的,而此文下面的代码示例都是基于此版本的)。
1 private void TestSelect() 2 { 3 Database db = Databases.NBBS; 4 ListresList = null; 5 6 DataSet resSet = Databases.NBBS.Select(NBBS.Tables.t_Board).ToDataSet(); 7 Console.WriteLine(resSet.Tables.Count); 8 9 //t_Board t_Board_Model = Databases.NBBS.Select(NBBS.Tables.t_Board).Where(NBBS.Tables.t_Board.Board_ID == 14 && NBBS.Tables.t_Board.Board_Place > 5).ToSingleObject (); 10 //Console.WriteLine(t_Board_Model.Board_Name); 11 12 string cmdText = Databases.NBBS.Select(NBBS.Tables.t_Board, NBBS.Tables.t_Board.Board_ID.Max()).Where(NBBS.Tables.t_Board.Board_Name.Like("nba")).ToDbCommandText(); 13 14 cmdText = Databases.NBBS.Select(NBBS.Tables.t_Board, NBBS.Tables.t_Board.Board_ID.Max().Alias("Max_Id")).Where(NBBS.Tables.t_Board.Board_Name.Like("nb%")).ToDbCommandText(); 15 cmdText = Databases.NBBS.Select(NBBS.Tables.t_Board, NBBS.Tables.t_Board.Board_ID.Max()).Where(NBBS.Tables.t_Board.Board_Name.Like("nb%")).ToDbCommandText(); 16 //object obj = Databases.NBBS.Select(NBBS.Tables.t_Board, NBBS.Tables.t_Board.Board_ID.Max()).Where(NBBS.Tables.t_Board.Board_Name.Like("nb%")).ToDbCommand(); 17 //obj = Databases.NBBS.Select(NBBS.Tables.t_Board, NBBS.Tables.t_Board.Board_ID.Max()).Where(NBBS.Tables.t_Board.Board_Name.Like("nb%")).ToDataReader(); 18 int max_Board_ID = Databases.NBBS.Select(NBBS.Tables.t_Board, NBBS.Tables.t_Board.Board_ID.Max()).Where(NBBS.Tables.t_Board.Board_Name.Like("nb%")).ToScalar ();//返回单个字段时,不要用ToList方法 19 20 string cmdText2 = Databases.NBBS.Select(NBBS.Tables.t_Board, NBBS.Tables.t_Board.Board_ID.Max(), QueryColumn.All()).Where(NBBS.Tables.t_Board.Board_Name == 2).ToDbCommandText(); 21 22 resList = db.Select(NBBS.Tables.t_Board, NBBS.Tables.t_Board.Board_Name).GroupBy(NBBS.Tables.t_Board.Board_Name).OrderBy(NBBS.Tables.t_Board.Board_Name.Desc).SetSelectRange(2, 2, NBBS.Tables.t_Board.Board_Name).ToList (); 23 ShowListCount(resList); 24 25 //级联查询 26 resSet = db.Select(NBBS.Tables.t_Board, QueryColumn.All(NBBS.Tables.t_Board), NBBS.Tables.t_MotherBoard.MotherBoard_Name) 27 .LeftJoin(NBBS.Tables.t_MotherBoard, NBBS.Tables.t_MotherBoard.MotherBoard_ID == NBBS.Tables.t_Board.MotherBoard_ID) 28 .OrderBy(NBBS.Tables.t_Board.Board_ID.Desc).ToDataSet(); 29 ShowDataSet(resSet); 30 31 #region MyRegion 32 //ds = db.Select(Northwind.Categories, QueryColumn.All(Northwind.Categories), QueryColumn.All(Northwind.Products)) 33 // .Join(Northwind.Products, Northwind.Products.CategoryID == Northwind.Categories.CategoryID) 34 // .Where(Northwind.Categories.CategoryName.Length > 3 && Northwind.Products.UnitPrice > 100) 35 // .OrderBy(Northwind.Categories.CategoryID.Asc, Northwind.Products.ProductID.Desc) 36 // .ToDataSet(); 37 38 //ds = db.Select(Northwind.Categories, QueryColumn.All(Northwind.Categories), QueryColumn.All(Northwind.Products)) 39 // .LeftJoin(Northwind.Products, Northwind.Products.CategoryID == Northwind.Categories.CategoryID) 40 // .Where(Northwind.Categories.CategoryName.Length > 3 && Northwind.Products.UnitPrice > 100) 41 // .OrderBy(Northwind.Categories.CategoryID.Asc, Northwind.Products.ProductID.Desc) 42 // .ToDataSet(); 43 44 //ds = db.Select(Northwind.Categories, QueryColumn.All(Northwind.Categories), QueryColumn.All(Northwind.Products)) 45 // .RightJoin(Northwind.Products, Northwind.Products.CategoryID == Northwind.Categories.CategoryID) 46 // .Where(Northwind.Categories.CategoryName.Length > 3 && Northwind.Products.UnitPrice > 100) 47 // .OrderBy(Northwind.Categories.CategoryID.Asc, Northwind.Products.ProductID.Desc) 48 // .ToDataSet(); 49 50 //ds = db.Select(Northwind.Categories, Northwind.Categories.__Alias("CategoriesAlias").CategoryName).Join(Northwind.Categories, "CategoriesAlias", Northwind.Categories.CategoryID == Northwind.Categories.__Alias("CategoriesAlias").CategoryID). 51 // SetSelectRange(2, 2, Northwind.Categories.CategoryID).Where(Northwind.Categories.CategoryName.Length > 0 && Northwind.Categories.__Alias("CategoriesAlias").Description != null). 52 // ToDataSet(); 53 54 //int pageSize = 10; 55 //int rowCount = (int)db.Select(Northwind.Categories, QueryColumn.All().Count()).ToScalar(); 56 //int pageCount = (rowCount % 10 == 0 ? rowCount / 10 : (rowCount / 10) + 1); 57 58 //Console.WriteLine(string.Format("pageSize={0}, rowCount={1}, pageCount={2}", pageSize, rowCount, pageCount)); 59 60 ////test select tosingleobject and tolist 61 //_Category cat = db.Select(Northwind.Categories).ToSingleObject<_Category>(); 62 ////Dictionary dic = db.Select(Northwind.Categories).ToSingleObject >(); 63 ////Hashtable hash = db.Select(Northwind.Categories).ToSingleObject (); 64 ////NameValueCollection nameval = db.Select(Northwind.Categories).ToSingleObject (); 65 //_Category[] cats = db.Select(Northwind.Categories).ToArray<_Category>(); 66 //NameValueCollection[] namevals = db.Select(Northwind.Categories).ToList (); 67 #endregion 68 }
如上是使用NBearLite的查询测试代码,看看上面的就可以大概知道其用法与我们手写SQL很相似,也比较简单易用,而且在功能上几乎可以满足所有的数据库查询操作,无论是级联还是分页查询。
1 private void TestUpdate() 2 { 3 try 4 { 5 string cmdText = Databases.NBBS.Update(NBBS.Tables.t_Board).AddColumn(NBBS.Tables.t_Board.Board_Name, NBBS.Tables.t_Board.Board_Name + "_" + DateTime.Now).Where(NBBS.Tables.t_Board.Board_ID == null).ToDbCommandText(); 6 int n = Databases.NBBS.Update(NBBS.Tables.t_Board).AddColumn(NBBS.Tables.t_Board.Board_Name, NBBS.Tables.t_Board.Board_Name + "_" + DateTime.Now).Where(NBBS.Tables.t_Board.Board_ID == 8).Execute(); 7 n = Databases.NBBS.Update(NBBS.Tables.t_Board).AddColumn(NBBS.Tables.t_Board.Board_Name, NBBS.Tables.t_Board.Board_Name + "_" + DateTime.Now).Where(NBBS.Tables.t_Board.Board_ID == "7").Execute(); 8 n = Databases.NBBS.Update(NBBS.Tables.t_Board).AddColumn(NBBS.Tables.t_Board.Board_Name, NBBS.Tables.t_Board.Board_Name + "_" + DateTime.Now).Where(NBBS.Tables.t_Board.Board_ID == "这不是数字").Execute();//此update 将会报错,类型不匹配 9 } 10 catch (Exception ex) 11 { 12 throw ex; 13 } 14 }
如上是使用NBearLite的修改测试代码,用法也同样的简单。
除此之外,它具有以下优点:
1.在执行SQL时,会将转换后的SQL中的参数变为参数化SQL。
2.其底层对SQL语句解析时,会根据inputType(如查询,通过sqlDataReader返回结果,其类型即为:sqlDataReader)和outType(如查询 返回的 Person实体集合,其类型即为:Person)等信息获得类型转换(Convert)key,这样再执行相似的SQL操作时,就直接(缓存)静态Dictionary中获得,——这是其性能突出关键之处。
说完Nbear的优点,再谈下我为什么不采用其它的框架(使用工具或框架要先对比分析下可选项中哪个更具优势):
1. 对于NHibernate, (学java时曾用过Hibernate),感觉其过于庞大,且性能也较差。
2.Linq(当时也想过用),虽然其写法也比较优雅或简便,但公司的同事(包括我自己)对其的使用都不熟练,也不清楚它是否会将最终的SQL转换为参数化SQL语句执行,也因为它作为C#的语法,如果想对其(如:转换后的SQL)进行调试,感觉就像是黑盒——不能或很能调试,去了解其内部执行情况。
好了,这篇就先写到这儿了,等深入了解研究后,再和大家分享。文后,附上NBearLite源码和自己的测试Demo, 建议对其感兴趣的朋友,研究下源码(源码我看了,感觉大牛写的就是有深度,有些地方还未理解),希望大家能互相交流学习。