zoukankan      html  css  js  c++  java
  • Winform开发之离线式WCF开发框架的实现介绍

    在上篇随笔《Winform开发框架之框架演化》中介绍了几种Winform开发框架,其中有对于离线式WCF开发框架的介绍,离线式的WCF开发框架 ,就是结合了传统Winform开发框架的数据访问方式,又利用了WCF分布式数据获取的特点,使得数据可以离线使用,在一种业务要求集中化,又要求不影响正常业务操作的应用系统场景下比较适合。本文主要介绍如何利用我的Winform开发框架的整体思路,实现WCF开发框架的离线式的数据上传、更新的同步操作。

    其实目前企业集中化管理,这种模式要求很多,如一些加盟店的情况,需要独立运行,有可以对一些总店关键数据进行提交或者下载,如客户信息等。这种情况下,就要求我们开发者提供适合应用场景的开发框架进行支持。离线式的WCF开发框架,一个特点就是基本上显示,以及保存等操作数据库的数据,都是本地的数据库,不是远端的服务器数据库,这样,就需要记录所有发生变更的数据库操作,包括写入,删除、修改等,以便在网络畅通的情况下,可以上传数据到服务器上面。

    下面我们来分析下这种离线式的WCF开发框架,需要做哪些准备工作,来实现框架的支撑。

    1、数据库表记录ID定义唯一性。

    这个是常见分布式系统的要求了,在一些普通的Winform程序的数据库中也比较常见,之所以把它作为第一条,虽然简单,但是很必要,因为需要避免分布式的客户端和服务端的数据冲突问题,特别在多个客户端的情况下,对数据的唯一性要有好的控制性。

    所以这也要求基础的框架基类,能够提供对整形、字符型的主键ID的操作兼容性,这在我的Winform开发框架中,支持是比较好的。

    2、多数据库支持

    在分布式的环境下,和服务端的环境不同,部署程序要求越简单越好,太复杂的话,增加客户端的使用的难度,会极大提高维护的成本,因此,一般客户端会选用适应性比较好,又免安装的数据库,如Sqlite就是一个很好的单机版数据库,还有Access也是很不错的,当然还有其他的一些数据库,不过我觉得Sqlite和Access是比较好的备选方案。服务器端的数据库,则看业务支持和响应程度来决定,可以从一些对性能支持比较好的数据库中选型,如大型一点的,可选择Oracle来做,其他的可以选择SqlServer、MySql等数据库。虽然这些数据库部署比较麻烦一点,不过反正只有一台服务器需要这种安装部署,所以工作难度及工作量不会很大。

    对多数据库的支持,也要求我们的开发框架能够很好兼容,最好在数据库操作层可以通过配置方式进行切换,即使数据库变化为其他类型,也不需要改变整体的框架布局,甚至不用变化代码即可实现自由切换,如数据库框架可以设置如下。

     

    对于上面几种数据库的支持,一般来说,需要增加不同数据库类型的BaseDAL,由于每个不同数据库都需要拥有一个BaseDAL,那么很多相同的操作代码就会发生冗余,因为大多数数据库的基础操作是一样的,只有一部分比较特别,需要进行个性化处理,因此对数据访问层进行优化设计,得到下面的设计图,如下所示。

    经过框架抽象,这个BaseDAL类代码很少,基本上通用的数据库操作,已经放到了AbStractBaseDAL超级基类进行封装,即使对于一些不同数据库操作不同,我们也尽可能抽象放到上面基类了,BaseDAL只需要实现一些特殊的操作即可。

     

    3、分布式客户端数据上传设计

    由于分布式,离线式的框架设计,要求我们客户端自行记录数据的变化情况,包括新增数据、修改数据和删除数据,这样不用每次同步的时候,把所有的数据库记录都遍历一次,然后和服务器记录进行比较。这种记录方式,可以极大提高客户端数据上传的性能和快捷性。因为我们对于很多表及记录的数据库,可能每次更新的只是一小部分,这样设计,有利于我们更好地额处理客户端数据上传。

    例如,下面的表,就是对于一个客户端上传记录表的设计,其中Dept_ID是用来记录不同部门的表示,基本上每个客户端,都有自己的一个部门编号,防止数据发生冲突,也方便服务器端的数据进行归类查询。

    下面是一些实际业务产生的数据记录,我们记录部门ID、表名(发生变化)、对应记录的ID(GUID)、修改用户、修改时间等信息。

    另外,我们还可以结合系统来记录用户登录信息、用户对记录修改的日志,以便我们对一些关键操作进行审计需要。数据库设计如下所示。

    4、数据修改记录自动记录

    对于上面的to_upload表,我们是把客户端修改的数据记录信息,记录到表里面去,但是这些肯定是后台自动记录的,而且这个操作是放到基类比较合适,否则每次调用,不太方便,也比较冗余。

    放到基类的操作,我们需要设计一下,否则所有的表都会记录,不管需不需要,这样不可以的。

    首先我们在基类BaseDAL(对Sqlite的数据库基类),增加一个变量来记录是否数据库访问基类,需要记录数据库变化信息。

    protected bool IsLogToUpoad = false; //表示是否记录变化

    对于具体业务对象的数据访问,我的Winform开发框架都有提供一个对应的类来进行操作。

        /// <summary>
        /// 药品信息
        /// </summary>
        public class DrugDetail : BaseDAL<DrugDetailInfo>, IDrugDetail
        {
            #region 对象实例及构造函数
    
            public static DrugDetail Instance
            {
                get
                {
                    return new DrugDetail();
                }
            }
            public DrugDetail() : base("M_DrugDetail","ID")
            {
                this.IsLogToUpoad = true;
                this.sortField = "EditTime";
                this.isDescending = true;
            }
    
            #endregion
    ..........................................

    为了要实现自动记录数据库变化信息,我们需要在BaseDAL里面对插入、修改、删除的操作进行特别的处理,重载基类的操作,增加相应的处理即可,如下代码所示。

            private void AddToUpload(string id, string targetTable, System.Data.Common.DbTransaction trans, int uploadType)
            {
                AppConfig config = new AppConfig();
    
                ToUploadInfo info = new ToUploadInfo();
                info.EditTime = DateTime.Now;
                info.RecordId = id;
                info.TableName = targetTable;
                info.UploadType = uploadType;
                info.Dept_ID = config.AppConfigGet("Dept_ID"); ;
                info.User_ID = config.AppConfigGet("User_ID");
                Hashtable uploadHash = GetHashByObject(info);
                base.Insert(uploadHash, "SS_ToUpload", trans);
            }
    
            public override bool PrivateUpdate(object id, Hashtable recordField, string targetTable, DbTransaction trans)
            {
                bool result = base.PrivateUpdate(id, recordField, targetTable, trans);
                if (result && IsLogToUpoad)
                {
                    AddToUpload(recordField["ID"].ToString(), targetTable, trans, 1);
                }
                return result;
            }
    
            public override bool Insert(System.Collections.Hashtable recordField, string targetTable, System.Data.Common.DbTransaction trans)
            {           
                bool result = base.Insert(recordField, targetTable, trans);
                if (result && IsLogToUpoad)
                {
                    AddToUpload(recordField["ID"].ToString(), targetTable, trans, 0);
                }
                return result;
            }

    由于是上面的PrivateUpdate和Inser方法,是所有派生的更新、插入接口的最原始的函数,所有其他相关函数都会调用这两个的基础函数, 这样就基本实现了数据库记录的变化记录了。

    5、分布式客户端数据和服务器端的同步

    为了和服务器实现同步,需要实现变化记录的上传和服务器修改数据的下载两个方向的工作。

    变化记录的上传从操作,就是遍历to_upload里面的记录,把它更新到服务器上即可。

            /// <summary>
            /// 把本地变化的数据记录,同步到服务器上
            /// </summary>
            /// <returns></returns>
            public bool SyncAll()
            {
                List<ToUploadInfo> toList = BLLFactory<ToUpload>.Instance.GetAll();
                int i = 1;
                int total = toList.Count;
                bool success = false;
    
                foreach (ToUploadInfo toInfo in toList)
                {               
                    switch(toInfo.TableName.ToLower())
                    {
                        case "m_drugusedetail":
                            success = DealDrugUseDetail(toInfo);
                            if (!success) return false;
                            break;
                          .......................................
                          //其他操作,利用服务器代理对象,实现各个表的数据上传   
                    }
    
                    #region 显示进度等处理
                    string tips = string.Format("正在同步表 {0}...", toInfo.TableName);
                    int step = 0;
                    if (total > 0)
                    {
                        step = Convert.ToInt32((100.0 / (1.0 * total)) * i);
                    }
                    if (OnDataDealed != null)
                    {
                        OnDataDealed(step, tips);
                    }
                    i++;
    
                    if (toInfo == null || string.IsNullOrEmpty(toInfo.TableName))
                    {
                        continue;
                    }
                    #endregion
                }
    
                #region 同步系统关键数据
                if (success)
                {
                    //部门
                    SynAllDept();
    
                    //已上传数据表同步
                    DealUploaded();
    
                    SyncBasicData();
                }
    
                #endregion
    
                return true;
            }

     为了实现数据上传操作,我们把逻辑封装在一个函数里面,这样方便管理,也方便阅读。

            private bool DealDrugUseDetail(ToUploadInfo toInfo)
            {
                bool success = false;
                DrugUseDetailInfo objInfo = BLLFactory<DrugUseDetail>.Instance.FindByID(toInfo.RecordId);
                if (objInfo != null && objInfo.Dept_ID == Portal.gc.LoginInfo.Dept_ID)
                {
                    new DrugUseDetailServiceClient().Using(client =>
                    {
                        success = client.InsertUpdate(objInfo, objInfo.ID);
                    });
    
                    if (success)
                    {
                        RemoveToUploadInfo(toInfo);
                    }
                }
                return success;
            }

    数据同步的下载操作,其实也不难,就是把数据对应的记录下载下来进行判断。

            private void DealInHospital()
            {
                List<InHospitalInfo> list = new List<InHospitalInfo>();
                new InHospitalServiceClient().Using(client =>
                {
                    list = client.Find(conditionPilotDept);
                });
    
                int i = 1;
                int total = list.Count;
                foreach (InHospitalInfo info in list)
                {
                    BLLFactory<InHospital>.Instance.InsertUpdate(info, info.ID);
                    ShowProgress(total, i++, "住院信息");
                }
            }
    主要研究技术:代码生成工具、会员管理系统、客户关系管理软件、病人资料管理软件、Visio二次开发、酒店管理系统、仓库管理系统等共享软件开发
    专注于Winform开发框架/混合式开发框架Web开发框架Bootstrap开发框架微信门户开发框架的研究及应用
      转载请注明出处:
    撰写人:伍华聪  http://www.iqidi.com 
        
  • 相关阅读:
    2019-2020-2 20175212童皓桢《网络对抗技术》 Exp4 恶意代码分析
    2019-2020-2 20175212童皓桢《网络对抗技术》Exp3 免杀原理与实践
    2019-2020-2 20175212童皓桢《网络对抗技术》Exp2 后门原理与实践
    2019-2020-2 20175212童皓桢《网络对抗技术》 Exp1 PC平台逆向破解
    2019-2020 《信息安全系统设计》20175212童皓桢 ucosii-2
    2019-2020-1 20175212_20175227《信息安全系统设计基础》
    实现mypwd
    2019-2020-1 20175212童皓桢《信息安全系统设计》实验四 外设驱动程序设计
    2019-2020-1 20175212童皓桢《信息安全系统设计》 实验三并发程序
    20175212-20175227 实验二 固件程序设计
  • 原文地址:https://www.cnblogs.com/wuhuacong/p/2797192.html
Copyright © 2011-2022 走看看