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++, "住院信息");
            }
        }

 本文转自博客园伍华聪的博客,原文链接:Winform开发之离线式WCF开发框架的实现介绍,如需转载请自行联系原博主。

时间: 2024-09-21 19:35:53

Winform开发之离线式WCF开发框架的实现介绍的相关文章

WCF开发框架形成之旅---结合代码生成工具实现快速开发

我的WCF开发框架推出很久了,一直有不少的朋友支持及提供良好的完善意见,随着利用这种基于Winform界面的WCF开发框架开发了不同类型的项目,各种WCF对象的调用及处理逐渐稳定及统一化,因此是时候让我的开发伴侣(代码生成工具Database2Sharp)来做更多更有技术性的工作了---提供基于我的WCF开发框架模式创建的项目工程及调用WCF的Winform界面处理代码.这样在WCF快速开发框架中,有了更强更高效率的支持,整个项目的开发,就更加是水到渠成,闲庭散步了. 因此,代码生成工具生成框架

基于我的Winform开发框架扩展而成的WCF开发框架

一直以来,多数时间在开发一些Winform共享软件,经过多年的积累,逐渐形成比较成熟稳定的Winform开发框架,并结合Web项目开发经验.代码生成工具.相关的控件开发及项目开发经验,逐渐形成一个相对比较完善的.NET开发体系.不过由于种种原因,甚少涉足WCF的相关应用,只是在09年初的时候,开发一个送水软件网络版的时候,玩过WCF,那时候主要是把WCF作为一个送水各种业务数据的同步服务实现.由于研究兴趣及工作便利等原因,最近学习研究,把WCF服务搭建在我传统的Winform开发框架基础上,完成

WCF开发框架之插件化应用模式升级

自从在<Winform开发框架之插件化应用框架实现>一文中,介绍并总结了Winform开发框架插件化应用框架的实现后,赢得了很多同行和客户的支持,于是把我的WCF开发框架.混合式开发框架都进行了升级,把它们都提升到插件化应用的高度上.本文主要介绍WCF开发框架,如何实现插件化的应用.从我随笔<基于我的Winform开发框架扩展而成的WCF开发框架>介绍可以看到,一般的WCF应用,是在客户端添加服务应用的方式,然后使用自动生成的WCF服务客户端代理来访问相应的服务的,这种方式比较方便

WCF开发框架的案例应用总结

在我的<Winform开发框架>系列文章中,除了介绍Winform开发框架外,还详细介绍了基于Winform开发框架的WCF开发框架,WCF开发框架除了具有Winform程序的丰富体验,绚丽的界面外,还具备Web应用程序的分布式应用特点,数据库服务端配置而不用客户端操心等特点,而随着.NET4.0的出现,只有40多M的安装包,也确实为WCF应用的推广使用更加方便.由于WCF应用的分布式这个重要的特点,客户数据全部保存在服务端,因此也提高了数据的安全性,因此很多传统应用的场合都可以使用WCF技术

我的WCF开发框架简化版及基于NET.TCP传输方式的实现

前面介绍很多关于我的WCF开发框架的文章,前面的介绍思路,主要是基于一个整个仓库管理系统来进行整体介绍的,本来另辟蹊径,着重介绍一个备件信息的表的在我的WCF开发框架中,各层是如何体现的,通过简单的一个表的操作,走完一个WCF开发过程,着重介绍一个对象类,如何实现整个wcf的应用.另外穿插介绍如何基于net.tcp传输方式实现wcf的应用,以及使用这种方式需要注重的地方等功能模块的介绍. 我们先来看看我的WCF开发框架整体架构设计图.   上图中,值得注意的是,WCF服务层,可以Host(寄宿)

WCF开发框架形成之旅--个人图片信息的上传保存

一般在业务系统里面,除了存储个人的基本信息外,可能也都需要存储个人的一些图片信息,通常如肖像.名片.身份证等重要图片信息,而这些信息偏小为了方便管理,一般也是和个人基本信息一起放在数据库里面的. 本人在开发形成自己的Winform开发框架及WCF开发框架过程中,对这些进行了优化整理,现公布出来和大家一起讨论学习,希望给大家提供一个参考外,自己有进一步的提升.本文主要以WCF开发框架下的个人图片信息上传保存作为主题,介绍其中涉及到的一些知识点和操作,以及规避其中一些常见的问题. 1)首先,我们需要

WCF开发框架形成之旅---终极WCF框架是什么样子的

前面几篇WCF框架的文章,一直是介绍我的WCF框架的形成中的知识,期间虽然我在工作项目中已经成功运用各种WCF的概念及特性,而且是多个部门之间的数据管理系统,基本上WCF框架的雏形已经形成了,不过我一直想把我成熟的Winform开发框架,提炼整合到WCF框架上,这样在成熟的Winform框架基础上应用的WCF技术,才是我整个WCF开发框架的终极形式,虽然项目时间很紧,但业余空闲时间我一直未曾停步,前阵子通宵达旦完成,并经过多番测试,今天有幸和大家分享一下这个WCF框架的真面目及其中的一些经验总结

Winform开发客户关系管理系统(CRM)总结 1 界面功能展示

一直以来,都希望整合一个以客户为中心的平台,有两个方面的考虑:一是实现客户数据.客户关系 .客户管理等方面的整合,以便更好利用好客户的相关资源,发挥最大的营销效益:二是整合目前我的 开发框架的所有模块和技术,包括权限管理和控制.字典管理模块.分页控件.公用类库.自动更新模 块.附件管理模块.邮件短信的信息通知模块.工作流模块,以及来电显示记录模块.群发邮件营销模 块.日历管理模块等方面的内容.本随笔系列主要介绍在开发我的CRM系统中的各种场景问题的解决思路 ,以及相关的功能实现,力求在逐步完善这

.Net Winform开发笔记(四)透过现象看本质_C#教程

写在前面: 从一个窗体的创建显示,再到与用户的交互,最后窗体关闭,这中间经历过了一系列复杂的过程,本文将从Winform应用程序中的Program.cs文件的第一行代码开始,逐步分析一个Winform应用程序到底是怎样从出生走向死亡,这其中包括Form.Show()和Form.ShowDialog()的区别.模式对话框形成的本质原因.消息循环.Windows事件与.net中事件(Event)的区别.System.Windows.Form.Application类的作用.以及我之前一篇博客中(.N