本博客所有文章分类的总目录:http://www.cnblogs.com/asxinyu/p/4288836.html
Newlife XCode组件相关文章目录:http://www.cnblogs.com/asxinyu/p/4329747.html
1.前言
1.QQ群:1600800
使用XCode已经3年了,谈不上精通,都是些基础功能使用,以前源码啃过很多次,了解过部分功能的实现细节,但终归是要应用的,当没有时间时,了解使用就可以了,所以现在更多关注业务相关的东西,数据库操作,XCode已经很完善了。本文就对这几年应用过程的一些问题,以及很多人经常问起来的问题进行一个总结。今天就介绍2个主要的,比较常见的使用:表达式查询,实体数据初始化。
我们将在下一篇博客中重点介绍更加重量级的分库分表功能,以及通用配置辅助类的使用。敬请关注。
如果文章或者资源对您有用,请“推荐”和关注,接下来还有很多.NET平台关于机器学习、彩票分析平台和预测的文章和资源待发表。
本文原始地址:http://www.cnblogs.com/asxinyu/p/4248281.html
2.简洁优雅的查询
XCode对查询语法和灵活性是我见过的ORM中最优雅的,最简单体贴的。XCode由于支持多种数据库,并且效率很高的原因就是在这些数据库核心操作的背后有许多精巧的设计,其支持的查询就是XCode灵活强大的表现之一,每天写着重复的sql,调试,拼接参数,真的很累,那么看看XCode中的查询,真的是赏心悦目,是一种享受吧。首先对XCode的查询语法进行一个简单的总结和描述:
1) XCode的查询很灵活,可以针对单个字段,也可以针对多个字段;例如:
1 var model1 = Find(_.Name, "中国"); 2 //下面2个结果是一样的,用的方法不一样 3 var model2 = Find(new String[] { _.Name, _.OnceName }, new object[] {"中国","China" }); 4 var model3 = Find(_.Name == "中国" & _.OnceName == "China"); 5 //同理看一个FindAll的使用 6 var modelList1 = FindAll(_.IsAsia, true);//只针对IsAsia字段 7 //FindAll的最常见使用:5个参数的,第一个是条件表达式,第二个是排序字段(ComanyID),第三个是选择的字段,null代表选择所有 8 //startIndex参数,代表起始行,默认都是从0开始,最后一个表示放回的数据行数,0代表所有行,可以只取前10。 9 var modelList2 = FindAll(_.IsAsia == true & _.IsAuthority == true, _.ComanyID, null, 0, 0);
2) XCode的查询是实体基类Entity<TEntity>封装好的静态方法,里面包含很多东西,建议熟练使用后的朋友,好好看一看,对理解XCode,更好的使用都有很大的好处。
3) XCode中查询满足条件的记录数有专门的FindCount方法;其方法原型和FindAll类似。
4) XCode有着非常完善的缓存体系,实体类是直接可以进行缓存设置和查询的,方法是FindAllWithCache; Meta.Cache.Entities中也有缓存数据,可以直接查询。例如:
1 // 实体缓存 2 Meta.Cache.Entities.FindAll(_.EventId, eventid); 3 Meta.Cache.Entities.Find(_.Id, id); 4 //单对象缓存 5 return Meta.SingleCache[id]; 6 FindAllWithCache(_.EventName, "西甲");
5) XCode的实体操作接口IEntityOperate中也有相对于的查询方法,使用与单个实体的Find和FindAll的使用基本相同。例如下面一段代码(2年前使用XCode迁移数据写的,非常好理解,也非常好的完成了迁移工作)。里面在对表进行处理的时候,就使用了IEntityOperate来操作,非常方便。其使用和原理可以看源码,和博客的其他文章。
1 /// <summary> 2 /// 拷贝数据库,只需要数据库连接字符串和源数据库即可 3 /// </summary> 4 /// <param name="originConn">源数据库连接字符串</param> 5 /// <param name="desConn">目的数据库连接字符串</param> 6 /// <param name="perCount">每次获取的记录数目,如果默认-1则会自动调用函数计算一个合理值</param> 7 public static void CopyDataBase(string originConn,string desConn,int perCount = -1) 8 { 9 //思路:通过源数据库获取架构信息,然后反向工程,然后导出数据 10 DAL dal = DAL.Create(originConn); 11 List<IDataTable> tableList = dal.Tables;//获取源数据库的架构信息 12 tableList.RemoveAll(t => t.IsView);//过滤掉视图 13 //首先拷贝数据库架构 14 DAL desDal = DAL.Create(desConn);//要在配置文件中启用数据库架构才行 15 desDal.Db.CreateMetaData().SetTables(tableList.ToArray()); 16 //然后依次拷贝每个表中的数据 17 foreach (var item in tableList) 18 { 19 //首先根据表名称获取当前表的实体操作接口 20 IEntityOperate Factory = dal.CreateOperate(item.Name); 21 //分页获取数据,并更新到新的数据库,通过更改数据库连接来完成 22 int allCount = Factory.FindCount (); 23 if (perCount < 0) perCount = GetDataRowsPerConvert (allCount ); 24 int pages = (int)Math.Ceiling ((double)((double )allCount/(double )perCount)); 25 for (int i = 0; i < pages ; i++) 26 { 27 Factory.ConnName = originConn; 28 IEntityList modelList = Factory.FindAll(string.Empty, string.Empty, string.Empty, i * perCount, perCount); 29 Factory.ConnName = desConn; 30 modelList.Insert(true); 31 } 32 Console.WriteLine("数据库{0} 数据转移完成!",item.Name ); 33 } 34 }
6) XCode中的查询表达式类型是 WhereExpression,实际中的SQL语句拼接的结果就是WhereExpression类型,而该类型的拼接支持 &,| 运算符的重载,可以直接将不同的条件组合在一起。拼接的字段名称为XX._.字段名,_的实体类型的用处也主要在这里,注意WhereExpression类型是可以隐式转换为String类型的。这也是为什么有人不解直接将WhereExpression类型放入FindAll第一个参数的原因,其实已经转换成String了。看看1个实际查询综合的例子(来源于大石头BBX项目中的代码):
1 /// <summary>获取有效的广告列表</summary> 2 public static EntityList<Announcement> GetAvailableList() 3 { 4 //return FindAll(_.StartTime < DateTime.Now & _.EndTime > DateTime.Now, null, null, 0, 0); 5 var now = DateTime.Now; 6 return Search(null, null, now, now); 7 } 8 9 /// <summary>查询符合条件的公告</summary> 10 /// <param name="poster">发布者</param> 11 /// <param name="title">标题</param> 12 /// <param name="start">开始时间</param> 13 /// <param name="end">结束时间</param> 14 public static EntityList<Announcement> Search(String poster, String title, DateTime start, DateTime end) 15 { 16 if (Meta.Count <= 0) return new EntityList<Announcement>(); 17 18 // 公告的总数一般不多,可以使用实体缓存 19 if (Meta.Count < 1000) 20 { 21 var list = Meta.Cache.Entities.ToList().AsEnumerable(); 22 23 // 使用Linq从实体缓存里面过滤需要的数据 24 if (!poster.IsNullOrWhiteSpace()) list = list.Where(e => e.Poster.Contains(poster)); 25 if (!title.IsNullOrWhiteSpace()) list = list.Where(e => e.Title.Contains(title)); 26 if (start > DateTime.MinValue) list = list.Where(e => e.StartTime > start); 27 if (end > DateTime.MinValue) list = list.Where(e => e.EndTime < end); 28 29 return new EntityList<Announcement>(list); 30 } 31 32 var exp = new WhereExpression(); 33 34 // 使用条件表达式构建查询SQL语句 35 if (!poster.IsNullOrWhiteSpace()) exp &= _.Poster.Contains(poster); 36 if (!title.IsNullOrWhiteSpace()) exp &= _.Title.Contains(title); 37 if (start > DateTime.MinValue) exp &= _.StartTime > start; 38 if (end > DateTime.MinValue) exp &= _.EndTime < end; 39 40 return FindAll(exp, null, null, 0, 0); 41 }
至于_.这种情况,可能有人刚开始看不懂,其实看看XCoder生成的实体类型代码就知道了。这个类型是快速访问字段用的,非常方便。
3.数据库的初始化,你难道还在手动或者用SQL?
这是一个很隐蔽的功能,应该有很多人刚入门的朋友没有注意到。这也是一个非常人性化的操作,在生成的“模型”里面,业务中有一个静态的构造函数InitData(),看看里面都有什么,这里举例是随便找的一个表,生成的结构相同,只不过字段不一样而已。虽然上面注释了,但很明显,这里是教大家怎么用的。在数据库反向工程执行的时候,首次连接数据库,就会执行这个方法,如果数据表是空的,那么程序就会自动执行指定的代码,进行数据插入。也就是说在你实际部署的时候,对于系统的初始化数据,根本不用去执行什么数据库SQL脚本,或者手动进行新建数据库和初始化的工作。
这一切都可以在程序里面迅速完成,而且非常简单,对于开发和测试来说,都非常简单,不需要你做任何管理。比如一些用户表和管理员表,可以初始化几个帐号;例如一些单位的部门信息,权限信息,都可以进行初始化。而且这一切都支持跨数据库,可以在几个数据库之间切换;而不是每一种数据库准备一套脚本。试想一下,开发机用sqlite开发,实际部署用mysql,而程序只需要改变一个连接字符串就可以自动初始化这些数据。
看看我的一个例子,下面是一个 欧洲赔率公司的 信息表,系统用到的赔率公司的数量不多,只有20条左右。因为,只要是新的环境,或者实际部署,系统就会根据下面的逻辑进行初始化工作。FastInsert是一个快速插入当前记录的方法,自己手动写的。
1 /// <summary>首次连接数据库时初始化数据,仅用于实体类重载,用户不应该调用该方法</summary> 2 [EditorBrowsable(EditorBrowsableState.Never)] 3 protected override void InitData() 4 { 5 base.InitData(); 6 if (Meta.Count > 0) return; 7 if (XTrace.Debug) XTrace.WriteLine("开始初始化{0}赔率公司数据……", typeof(CompanyInfo).Name); 8 9 #region 数据保存 10 FastInsert("平均赔率", 1000, true, false, false, true); 11 FastInsert("竞彩官方", 999, true, false, false, true); 12 FastInsert("威廉希尔", 252, true, false, false, true); 13 FastInsert("立博", 251, true, true, false, true); 14 FastInsert("bet 365", 469, true, true, false, true); 15 #region 其他公司 16 FastInsert("Interwetten", 122, true, false, false, true); 17 FastInsert("SNAI", 179, true, false, false, true); 18 FastInsert("bwin", 65, true, false, false, true); 19 FastInsert("伟德", 253, true, true, false, true); 20 FastInsert("易胜博", 254, true, true, false, true); 21 FastInsert("澳门", 247, true, true, false, true); 22 FastInsert("Expekt", 92, true, false, false, true); 23 FastInsert("Coral", 77, true, false, false, true); 24 FastInsert("Iceland", 117, true, false, false, true); 25 FastInsert("Oddset", 142, true, false, false, true); 26 FastInsert("皇冠", 300, true, false, false, true); 27 FastInsert("利记sbobet", 169, true, true, false, true); 28 FastInsert("金宝博", 250, true, true, false, true); 29 FastInsert("10BET", 1, true, true, false, true); 30 //2014-05-08 增加亚盘公司,大小盘公司和进球公司 31 FastInsert("明陞", 566, false, true, true, true); 32 #endregion 33 FastInsert("12BET", 116, false, true, false, true); 34 #endregion 35 36 if (XTrace.Debug) XTrace.WriteLine("完成初始化{0}赔率公司数据!", typeof(CompanyInfo).Name); 37 } 38 39 /// <summary>快速插入公司信息,只在内部初始化的时候用</summary> 40 static void FastInsert(String name, Int32 companyId, Boolean isEurop, Boolean isAais, Boolean isTrade = false,
Boolean isAuthority = false) 41 { 42 var entity = new CompanyInfo(); 43 entity.Name = name; 44 entity.OnceName = String.Empty; 45 entity.ComanyID = companyId; 46 entity.IsTrading = isTrade; 47 entity.IsAuthority = isAuthority; 48 entity.IsEurope = isEurop; 49 entity.IsAsia = isAais; 50 entity.Insert(); 51 } 52 #endregion
数据库的主要操作就十分增删查改,其中查询应该是最频繁的操作,在XCode中用好查询,不仅仅是会写查询,还要灵活运用XCode支持的三级缓存。要自己花点功夫去研究源码,当然X组件的视频和很多博客都有讲解到,可以去论坛和本文的博客中去寻找。