[转帖]用Xcode搞定任何数据库迁移_Android, Python及开发编程讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  Android, Python及开发编程讨论区 »
总帖数
1
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 5078 | 回复: 0   主题: [转帖]用Xcode搞定任何数据库迁移        下一篇 
baijiang.lu
注册用户
等级:少校
经验:947
发帖:81
精华:0
注册:2013-9-2
状态:离线
发送短消息息给baijiang.lu 加好友    发送短消息息给baijiang.lu 发消息
发表于: IP:您无权察看 2013-9-11 15:01:51 | [全部帖] [楼主帖] 楼主

陆陆续续用Xcode组件将近一年了,作为一个业余开发者,很感谢大石头和他的团队。不仅感谢他们创造如此艺术的组件,更感谢他们耐心的指点,我才学会了使用模板,来开发始于自己风格和功能的通用组件。作为了老的动软代码生成器的使用者,但我接触并学会使用Xcode后,以及2年来在博客园看到的各类开发框架和ORM,我不得不说Xcode是我见过最强大的,小巧,精悍。

    很早就想写一篇教程,可能是基础比较差,写不出什么高质量的文章,毕竟是业余开发者。可能我的表述很多不专业,只有我自己理解,我也只需要对自己有用的功能。今天写这篇博文主要是受大石头的启发,因为越来越多的人使用Xcode,群里面的人都爆了,但是他们又没有太多时间来重复回答这些新手的问题,所以需要大家自力更生,看源码去学会使用。为了贡献自己对Xcode的理解和使用经验,使得后来学习的人更加容易,所以才有了我的这篇文章,写得不好,请拍砖,但拒绝人生攻击。

    1.事情起因

    NewLife.CommonEntity里面封装了一些通用实体类,今天自己做一个小工具(个人喜好,玩玩的),想得到这些通用实体类的数据字典,虽然知道有数据库反向工程的功能,但就是懒得动手。所以一开始手抄抄,然后在群里面哄了一下,然后群主大石头提示了一个CheckTables方法,其他的当然只能靠自己看源码了。其实往往很多帮助也只需要这么关键的一个提示,然后自己去学习。

    2.关于数据库方向工程:就是通过配置文件切换数据库连接字符串,不需要任何操作,系统会根据实体类自动生成数据库及数据表。很多ORM虽然可以通过配置文件修改数据库连接字符串,但还是需要在目标数据库中新建好表,因此多少有些繁琐,而Xcode彻底屏蔽了这些东西,不必要关心数据库。因此从给一个数据库转化到另外一个数据库,是再方便不过。

    3.解决过程

    在石头的提示下(CheckTables),我找到了这个方法所在的类DAL(数据访问层),看看这个方法:

1 /// <summary>检查数据表架构,不受反向工程启用开关限制</summary>
2 public void CheckTables()
3 {
4 WriteLog("开始检查连接[{0}/{1}]的数据库架构……", ConnName, DbType); 5
      6 Stopwatch sw = new Stopwatch();
      7 sw.Start();
      8 try
      9 {
            10 List<IDataTable> list = EntityFactory.GetTables(ConnName);
            11 if (list != null && list.Count > 0)
            12 {
                  13 // 全都标为已初始化的
                  14 foreach (IDataTable item in list)
                  15 {
                        16 if (!HasCheckTables.Contains(item.Name)) HasCheckTables.Add(item.Name);
                  17 }
                  18
                  19 // 过滤掉被排除的表名
                  20 if (NegativeExclude.Count > 0)
                  21 {
                        22 for (int i = list.Count - 1; i >= 0; i--)
                        23 {
                              24 if (NegativeExclude.Contains(list[i].Name)) list.RemoveAt(i);
                        25 }
                  26 }
                  27 // 过滤掉视图
                  28 list.RemoveAll(dt => dt.IsView);
                  29 if (list != null && list.Count > 0)
                  30 {
                        31 WriteLog(ConnName + "待检查表架构的实体个数:" + list.Count);32
                        33 Db.CreateMetaData().SetTables(list.ToArray());
                  34 }
            35 }
      36 }
      37 finally
      38 {
            39 sw.Stop();40
      41 WriteLog("检查连接[{0}/{1}]的数据库架构耗时{2}", ConnName, DbType, sw.Elapsed);
      42 }
43 }

;

    一开始看到这里,感觉不是我想要的,因为DAL里面需要传入ConnName,这里有点费解,既然要反向工程,那么数据库肯定不存在表结构,那传入ConnName有什么用?

    但是看到这但代码,我知道了,反向工程主要是通过获取实体类的IDataTable来完成的,就是上面代码第33行 Db.CreateMetaData().SetTables(list.ToArray());

    这里才是最关键的,呵呵。既然上面这个函数不满足我的要求,那就重新写一个满足要求的,所以我在DAL里面给CheckTables加了一个重载方法,如下所示:

1 public void CheckTables(List<IDataTable> list)
2 {
3 WriteLog("开始检查连接[{0}/{1}]的数据库架构……", ConnName, DbType);
      4 Stopwatch sw = new Stopwatch();
      5 sw.Start();
      6 try
      7 {
            8 if (list != null && list.Count > 0)
            9 {
                  10 WriteLog(ConnName + "待检查表架构的实体个数:" + list.Count);
                  11 Db.CreateMetaData().SetTables(list.ToArray());
            13 }
      14 }
      15 finally
      16 {
            17 sw.Stop();
      18 WriteLog("检查连接[{0}/{1}]的数据库架构耗时{2}", ConnName, DbType, sw.Elapsed);
      19 }
20 }

;

    有了上面的这个函数,只需要把自己想要反向工程的实体类列表传入进去就可以了,下面是我的调用方法:

1 List<IDataTable> list = new List<IDataTable>();
2 list.Add(Administrator.Meta.Table.DataTable);
3 list.Add(Area.Meta.Table.DataTable);
4 list.Add(Category.Meta.Table.DataTable);
5 DAL dal = DAL.Create("Common");
6 dal.CheckTables(list);

;

    简单的几行代码,就将 NewLife.CommonEntity中的几个表的结构自动生成到数据库了。我印象中记得,可以一下子获取 NewLife.CommonEntity所有的 List ,一时也想不起来,所以就只能一个个添加,呵呵,先解决实际问题,其他的再慢慢来搞。

    4.继续分析,虽然上面解决了的实际问题,但没有对反向工程的整个过程有更深入的了解。而且也萌生了念头,如此方便,那岂不是很容易的将数据库进行迁移,表结构和数据都很容易迁移到其他数据库平台了,正好闲着没事,写了一段简单的代码,调试看看【刚开始调试了半个小时,马马虎虎,有点晕,晚上回来继续奋战3个小时,才有点眉目,也难怪,大石头的团队花了好多年的成果,我怎么可能这么短时间就消化掉】。代码很简单,新建一个管理员,赋值并插入数据,没有数据库:

1 Administrator user = new Administrator();
2 user.Name = "admin";
3 user.Password = DataHelper.Hash("admin");
4 user.DisplayName = "超级管理员";
5 user.RoleID = 1;
6 user.IsEnable = true;
7 user.Insert();

;

    断点调试上述代码,记下主要内容吧:

    1.在new对象的过程中,会调用基类的构造函数 TEntity entity = new TEntity();然后字段赋值

    2.在对象插入到数据库中的过程中(user.Insert())会调用基类的 Insert()方法,在此方法中,有一个Valid(Boolean isNew)方法用来验证实体的数据是否符合要求,在检查实体数据过程中,会到数据库中获取一定的信息,如果数据表不存在,就会新建数据库和相应的表结构。这一部分涉及到的类挺多的,我也有些晕。大体如下吧,可能会有理解不到位:

    2.1 为了验证数据,需要判断该数据是否在数据表中已经存在,所以有了Entity.cs中的CheckExist方法,其中有一个FindCount(names, values)去数据库获取满足记录的条数。

    2.2 然后获取查询条件,调用Entity.Meta中的QueryCount方法,然后QueryCount调用WaitForInitData方法进行 检查并初始化数据,这时会对实体类进行检查。

    2.3 实体类第一次检查模型时,会调用Entity.Meta中的CheckModel()方法,这其中会对表结构的ModelCheckModes进行检查,ModelCheckModes分为2种情况,1种是初始化时反向工程,一种是使用时反向工程。Xcode连这一点多考虑到了,说明是多么的细致,因为在我看来即使是初始化时进行,也没有多少时间。TableItem有一个ModelCheckMode属性,会去获取实体类的ModelCheckMode,这个实现用到了Attribute,如果实体类声明了ModelCheckModeAttribute,那么获取到的就是这个值,如果没有声明,就是CheckAllTablesWhenInit。




赞(0)    操作        顶端 
总帖数
1
每页帖数
101/1页1
返回列表
发新帖子
请输入验证码: 点击刷新验证码
您需要登录后才可以回帖 登录 | 注册
技术讨论