忙忙碌碌有一年!做了很多东西,到头来,似乎又什么都没有做。人继续变老,程序继续改进。
这段时间从我们各个系统抽取了基础的常用的部分,整理后形成了一个XCode示例项目,包含三部分:DLL引用程序集、Web网站、YWS实体类库。
之前发布了一些介绍XCode的文章,有些朋友希望能得到源码,更多的朋友是想知道怎么用,想试一试!我们现有的系统是一个大体系,分割开来无法独立工作,所以一直没有提供XCode的例子项目。现在整理的这个例子项目,用到了XCode中常用的70%功能,蕴含着XCode开发模式的思想,希望能加深大家对XCode的了解。
XCode v3.5源码(及相关组件、例子、代码生成器等)目前存放于CodePlex,地址:http://xcode.codeplex.com/
充血模型,我们把它做得极其的大,所以才有了很多看似不可能的功能,我们不知道对与错,至少这么多年都走过来了(本文后面附上XCode开发日志,见证了XCode的风风雨雨)。
其中的泛型基类,很多朋友看起来都觉得很晕
/// <summary> /// 管理员 /// </summary> /// <typeparam name="TEntity">管理员实体类</typeparam> /// <typeparam name="TRoleEntity">角色实体类</typeparam> /// <typeparam name="TMenuEntity">菜单实体类</typeparam> /// <typeparam name="TRoleMenuEntity">角色菜单实体类</typeparam> /// <typeparam name="TLogEntity">日志实体类</typeparam> public partial class Administrator<TEntity, TRoleEntity, TMenuEntity, TRoleMenuEntity, TLogEntity> : Administrator<TEntity> where TEntity : Administrator<TEntity, TRoleEntity, TMenuEntity, TRoleMenuEntity, TLogEntity>, new() where TRoleEntity : Role<TRoleEntity, TMenuEntity, TRoleMenuEntity>, new() where TMenuEntity : Menu<TMenuEntity>, new() where TRoleMenuEntity : RoleMenu<TRoleMenuEntity>, new() where TLogEntity : Log<TLogEntity>, new() {
这个泛型类带有五个泛型参数,而每一个泛型参数都有相应的约束,所继承的基类本身也是泛型类。这种泛型的设计方式,让我们能够抽象大量公共操作。当然,面向对象中的抽象和虚拟也可以抽象,但是我们这里通过泛型基类,还可以抽象静态方法的实现,这也是我们大量使用泛型基类的原因。
有时候为了方便,会用一点匿名函数,如果匿名函数里面再用匿名函数,就会让人发疯,如果匿名函数再跟泛型混起来使用,那是……
/// <summary> /// 拥有权限的菜单 /// </summary> [XmlIgnore] public virtual EntityList<TMenuEntity> MenuList { get { return GetExtend<TMenuEntity, EntityList<TMenuEntity>>("MenuList", delegate { EntityList<TMenuEntity> list = EntityList<TMenuEntity>.From<TRoleMenuEntity>(Menus, delegate(TRoleMenuEntity item) { return Menu<TMenuEntity>.FindByID(item.MenuID); }); if (list != null) list.Sort(Menu<TMenuEntity>._.Sort, true); return list; }); } set { Extends["MenuList"] = value; } }
以上举了XCode开发模式中两个很特别的地方。(这年头,我们追求各家之长,大家都有的就不拿出来现啦!)
下面我们看看这个例子项目都有哪些亮点
1,自动创建数据库、数据表,这是XCode自身支持的功能。XCode有一个设置DatabaseSchema_Enable,打开后,每次启动网站,都将检查表结构,如果数据库或者数据表不存在,将会根据实体类信息自动创建,如果数据表结构不一致,将会自动修改。目前支持Access、SQLite和MSSQL,其中MSSQL支持最完善,其它Oracle和MySQL等,随着版本升级,很久没有测试过。而创建什么数据库,Access、SQLite还是MSSQL,由连接字符串觉得,XCode所要做的第一个工作就是检查现在的连接字符串对应着哪一种数据库,以及版本(MSSQL中很重要)。在这里,XCode的任务就是构造一个适合系统工作的数据库环境!
2,自动初始化数据。该功能由通用实体类组件CommonEntity实现。比如管理员实体类,在实体类的静态构造函数中,检查管理员表的数据,如果数据行数为0,表明没有任何数据,这个时候,代码将创建一个用户名和密码都是admin的默认管理员,并写入数据表。其它的还有角色、菜单、权限等初始化。配合上面第一个功能,这种设计让系统的部署变得非常简单。只要配置好连接字符串,告诉系统你要用什么数据库,系统将会为你完成一切数据库部署工作。
看看初始化之后的系统
3,树形实体。菜单和权限页面的树形结构,有几个特点:没有使用路径字段,只有简单的ParentID字段;菜单互相嵌套不会死循环,使用栈代替递归构造菜单树;不会大量读取数据库,因为有实体缓存,不仅缓存了每一个实体,还缓存了整颗树。页面上没有太多的实现代码,甚至在通用实体类组件里面的菜单基类,也没有太多的代码,因为菜单基类也是继承自树形实体基类EntityTree,后面的客户类别属于树形实体,也是继承自它。
4,模版生成。很多页面都是在模版生成的基础上稍作修改,风格统一。
XCode例子项目会持续更新,可以从QQ群(10193406)的SVN上拿到最新的源码,我们也会定期发布到CodePlex上!
XCode v3.5源码(及相关组件、例子、代码生成器等)目前存放于CodePlex,地址:http://xcode.codeplex.com/
附(XCode版本日志):
/*
* XCode的重大改进
*
* v6.0 增强的缓存和扩展属性支持
* v5.0 弱类型支持
* v4.0 实体集合和缓存
* v3.0 增加ORM的各种细节支持
* v2.0 数据架构功能,实体和数据结构双向映射
* v1.2 使用泛型基类
* v1.0 创建XCode
* /
/*
* v6.5.2010.1223 修正SQLite已知的一些问题,查找dll文件路径不正确,执行插入语句不正确
* IEntity增加CopyFrom方法,用于从指定实体对象复制成员数据
* 增加对二进制字段的支持,表现为Byte[]
*
* v6.4.2010.1217 修正Entity中CheckColumn无法正确计算选择字段的错误
* 优化SelectBuilder,允许Where中使用GroupBy字句,ToString时自动分割到正确位置
* 实体类增加静态方法FindByKeyForEdit,用于替代模版生成中的FindByKeyForEdit,为将要实现的表单基类(自定义表单)做准备
* ********************************
* 实体基类继承自BinaryAccessor,IEntity增加IIndexAccessor接口和IBinaryAccessor接口,增加对快速索引访问和二进制访问的支持
* 快速索引访问:实体类可以不必生成索引器代码,IIndexAccessor直接提供按名称访问属性
* 二进制访问:支持把实体对象序列化成二进制或者反向操作
* 这两个功能尚未经过严格测试,请不要用于正式系统使用!
*
* v6.3.2010.1209 修正实体工厂EntityFactory缓存实体导致无法识别后加载实体程序集的错误
*
* v6.2.2010.1202 SQLite增加读写锁,限制同时只能指定一个Excute操作
* Entity的PageSplitSQL方法修正表名没有进行格式化的BUG
*
* v6.1.2010.1119 取消依赖XLog,升级为依赖NewLife.Core,部分公共类库移植到NewLife.Core
* 修正EntityTree中FindChilds错误,增加排序字段的支持,如果指定排序字段,查询子级的时候讲按排序字段降序排序
* 取消授权限制,但仍然混淆代码
*
* v6.0.2010.1021 增加字典缓存DictionaryCache
* 增加弱引用泛型WeakReference<T>
* 单对象实体缓存改为弱引用,使得缓存对象在没有引用时得到回收
* 单对象实体缓存默认填充方法改为实体基类的FindByKey(前面某个版本增加,参数为Object),据说Delegate.CreateDelegate出来的委托会很慢
* 实体元数据类Meta增加单对象实体缓存SingleCache,给SingleCacheInt和SingleCacheStr加上过期标识,到v7.0将不再支持
* 实体元数据类Meta增加OnDataChange的数据改变事件,并使用弱引用,当该实体有数据改变后,触发事件,可用于在外部清楚该对象的缓存
* (重要更新)实体基类增加字典缓存Extends,用于存储扩展属性,并增加专属的GetExtend方法用于获取扩展属性,向依赖实体类注册数据更改事件
* (重要更新)实体树类升级为实体树基类,所有具有树形结构数据的实体类,继承自该类,享受树形实体的各种功能
* 实体基类增加虚拟的CreateXmlSerializer,允许实体类重载以改变Xml序列化行为,默认序列化行为改为序列化为特性
* EntityList改变序列化行为,默认序列化为特性
* EntityList判断元素是否存在Contains方法改为Exists
* EntityList增加多字段排序方法Sort,可用于多个字段排序
* 修复快速访问方法、属性和字段所存在的问题,在实体基类索引器使用
*
* v5.9.2010.1020 修正Database中QueryCountFast的严重错误
*
* v5.8.2010.1018 增加实体树接口IEntityTree,用于解决实体树操作的一些共性问题,避免死循环
*
* v5.7.2010.0930 XField中增加一个Table属性指向自己的XTable,创建XField时必须指定所属XTable
* 增加只读列表,各配置项使用只读列表返回,配置项自身检测列表是否被修改
* 实体操作接口增加Fields和FieldNames属性
*
* v5.6.2010.0909 修改DAL,把QueryTimes和ExecuteTimes改为本线程的查询次数和执行次数
* 修改Entity,Meta.Count返回表的总记录数(快速),FindCount()使用普通方法查询真实记录数
*
* v5.5.2010.0903 实体操作接口IEntityOperate返回的实体集合改为EntityList<IEntity>,因为使用操作接口时一般不知道具体类型,如果知道就没必要使用操作接口
* 增加数据连接名映射的配置,允许通过配置修改某一个实体或者某一个连接名实际对应的连接名
* 修改实体缓存和单对象缓存,使得缓存的数据因连接名或表名不同而不同,避免不同连接名或表名时缓存串号的问题
* 修改实体类结构模型,比如Area:Area<Area>:Entity<Area>,使得实体类可以通过继承实现二次扩展
*
* v5.4.2010.0830 数据架构中的异步检查BeginCheck当启用检查时改为同步检查Check,保证数据库操作前先完成一次数据架构检查
* 唯一键为自增且参数小于等于0时,返回空
* 实体操作接口IEntityOperate增加ToList方法,实现把ICollection转为List<IEntity>
* 优化Entity的FindAll方法,处理海量数据尾页查询时使用优化算法
*
* v5.3.2010.0826 DAL增加CreateOperate方法,为数据表动态创建实体类操作接口,支持在没有实体类的情况下操作数据库
* 该版本为不稳定版本
*
* v5.2.2010.0726 IEntity接口增加SetItem方法,提供影响脏数据的弱类型数据设置
* IEntityOperate接口增加Create方法,提供创建被类型实体对象的功能
*
* v5.1.2010.0709 增加实体接口、实体操作接口、实体基类的基类,提供弱类型的Orm支持
*
* v5.0.2010.0625 DAL优化
* 重新启用授权管理
* EntityList增加排序方法Sort
*
* v4.9.2010.0430 使用SelectBuilder来构造SQL语句,用于各层之间传递,准备将所有方法往SelectBuilder过度。该更新可能造成使用GroupBy的地方计算出错
*
* v4.8.2010.0325 修改Entity索引器,新的快速调用方法在set的时候有问题
* 增加常用查询方法为Web方法
*
* v4.8.2010.0301 增加实体类多表支持和多数据库支持
* 暴露几个常用的实体类静态方法供WebService引用
*
* v4.7.2010.0130 数据架构中识别表名时不应该区分大小写
* Entity中增加MakeCondition方法,以便于构造where语句
*
* v4.6.2009.1226 改善分页算法,产生更简单的分页语句
*
* v4.5.2009.1127 增加单实体缓存
*
* v4.4.2009.1125 修改二级缓存,Entities改为EntityList类型,非空,支持FindAll操作
*
* v4.3.2009.1121 修正Entity中Save方法判断自增字段不准确的BUG
*
* v4.2.2009.1114 优化SqlServer取架构信息的性能,以及输出的SQL的可读性
* 支持Sql2008,通过Sql2005类
* 优化QueryCount方法,产生更简短的SQL
*
* v4.1.2009.1028 增加快速获取单表总记录数方法QueryCountFast,修改Entity,在记录数大于1000时自动使用快速取总记录数
*
* v4.0.2009.1011 增加实体类集合EntityList,Entity的所有FindAll返回EntityList
* 增强数据架构功能,支持Access、SQL2000、SQL2005
*
* v3.7.2009.0907 修正DatabaseSchema中的一个小错误
*
* v3.6.2009.0819 修正FindCount方法的错误
*
* v3.5.2009.0714 Config类输出的FieldItem集合改为数组,防止被外部修改。
* 所有Select语句,使用*表示所有列,而不是列出所有列名。
*
* v3.4.2009.0701 修正SqlServer 2000取主键的错误
*
* v3.3.2009.0628 修改DAL,屏蔽Web请求级缓存DB的方法,似乎Web下多线程很不稳定,从而导致事务无法正常使用。
*
* v3.2.2009.0623 修改Oracle,重载GetTables方法,修正无法从Oracle数据库取得构架信息的错误
*
* v3.1.2009.0611 修改SqlServer类,使得每次返回构架信息时,都是从数据库取值。
*
* v3.0.2009.0608 元数据类Meta增加一个字段名列表属性FieldNames
* 调整DatabaseSchema类,新增字段时,直接设置默认值,否则对于非空字段,创建字段将会失败
* 数据构架增加DatabaseSchema_Exclude配置项,用于指定要排除检查的链接名。
* Entity中,增加ToXml输出的Xml的编码为UTF8,增加FromXml反序列化,增加Clone方法和CloneEntity方法
* Database中,增加事务计数字段,支持多级事务。
* Entity中,集合运算返回值改为List<T>,而不是IList<T>,更方便调用
* 在Database的QueryCount方法增加自动去除排序子句的功能
* Entity中,增加ToString重载,默认显示Name属性
* Entity中,Update时,增加了脏数据的判断,非脏数据的字段不更新,由于该功能的增加将导致以前所有的实体都无法Update到数据库,故版本改为3.0
*
* v2.3.2009.0530 修正非自增字段做主键时也调用InsertAndGetIdentity的错误。
*
* v2.2.2009.0527 数据表结构中,增加Int16和Int64两种类型
*
* v2.1.2009.0408 修正DAL中_DBs空引用的问题,可能是因为该成员是线程静态,并没有在每一个线程上new一个对象。
*
* v2.0.2009.0408 增加数据架构的功能。数据架构可以实现通过实体类反向更新数据库结构,不启用时,仅把更新SQL写入日志
* 修正Access类使用当前目录时拼接路径的错误。
*
* v1.2.2008.01.01 使用泛型基类重构
*
* v1.1.2007.03.08 大量扩展功能,支持自定义表单、广义单点登录等项目
* 完善对Oracle的支持,支持电力生产管理系统等项目
* 完善对Sybase的支持,支持电力SCADA数据分析等项目
*
* v1.0.2005.10.01 创建项目
* 支持C++客户端网络验证系统等项目
* 支持图片验证码识别等项目
*/