zoukankan      html  css  js  c++  java
  • 多层架构下的一个进销存项目

    花了点时间完成了一个进销存的项目,个人觉得对逻辑分析,架构思想都有一定的体会,故拿出来和大家分享下,首先介绍下项目的功能吧,主要功能有采购管理,销售管理,库存管理,人员信息管理,系统管理等,不过写这篇博客的主要目的并不是讲解如何实现项目功能,而是分享下该项目的架构思想、实现步骤和碰到的一些问题,分享下心得体会罢了......

       下面直接开始进入主题,首先贴上项目的主界面,由于对界面要求不是很高,所以界面相对来说比较简单,甚至可是说是简陋了,,呵呵,不过重点不在界面上,勇敢的直接上图:

     

    架构: 

    首先说说项目架构吧,,贴上项目模块图:

    从图中可知,项目总共分10个模块,采用三层架构+WCF+反射+抽象工厂来搭建,其中还加入了单例模式缓存机制。下面分别说说每个模块的作用:

    Insigma.PSI.UI:WinForm界面层

    Insigma.PSI.Model:模型层,数据实体   
    Insigma.PSI.IBLLService:业务逻辑接口层,是定义逻辑层的契约层
    Insigma.PSI.BLLService:业务逻辑实现层,是对接口的实现
    Insigma.PSI.IDAL:数据访问接口层,是定义访问层的契约层
    Insigma.PSI.SqlServerDAL:数据访问实现层,实现访问接口层,主要是针对SQL数据库
    Insigma.PSI.OracleDAL:数据访问实现层,实现访问接口层,主要是针对Oracle数据库  
    Insigma.PSI.Utility:工具层,主要存放了Oracle数据库,SQL数据库的数据库操作类

    Insigma.PSI.DBFactory:抽象工厂层,主要为考虑可以使项目可以适用Oracle数据库和SQL数据库,就搭建了一个抽象工厂层,分别在Oracle数据库层和SQL数据库层建立一个 工 厂来实现该抽象工厂

    C:\..\WcfWebRelease\:web层,主要用来发布WCF服务

    项目: 

     简单的分析完了框架的每个模块的作用,然后讲讲项目,由于篇幅问题,无法讲解项目的所有功能,所以在这里就拿出一个模块来讲解下,我选择了库存模块

     

    从图中可知,库存模块主要实现四个模块的功能,即库存列表、出库/入库、库存明细、库存警报 

    首先看看库存列表,上图:

     

    库存列表的功能比较简单,只是实现了仓库的增、删、改、查,由于功能比较简单,也就不多做讲解了....

    再贴上出库/入库模块图:


     

    这块应该算是库存模块中的核心模块了,因为该块的业务逻辑比较多,比较繁琐,大致讲讲业务逻辑吧,大致的逻辑为:出库单/出库单-->填写订单-->出库/入库-->修改库存信息,按照这个顺序来完成入库出库,顺序不能颠倒,同时还要实现订单的删除,修改,在修改库存信息时由于表和表之间有很多的外键关系,所以要同时删除多张表中含有删除信息的内容,实现联级删除,由于这里考虑到要保证结果的一致性,所以用事务来实现。再看看界面,为了保证用户按照这个逻辑顺序操作,首先我添加了一对单选框(出库单,入库单),当单选框都没有选中时,保存订单按钮、出库、入库按钮都是不可用状态,当用户选择了订单类型之后,保存订单按钮转为可用状态,需要用户填写订单信息,填写好对应信息之后保存订单,保存成功之后列表框中出现刚生产的订单,同时订单号是自动来生成的,入库单是“S_I”开头,出库单是"S_O"开头,后面五位数字为随机生成,这样生成的订单号易于区别,也避免了订单号的重复,然后根据用户选择的订单类型,对应的按钮转为可用(出库单-->出库按钮) ,这样就保证了用户始终是按照这个顺序来操作,同时订单列表框下有删除订单按钮,点击可以删除选中按钮。

    下面那出库为例,看看如何实现入库:

    点击【入库】按钮,弹出商品选择窗口,窗口中显示了订单号和仓库编号,同时还有一个【选择】按钮,通过该按钮选择商品 

     

    点击【选择】按钮,弹出商品列表窗口,由于我这里商品记录比较少,只有两条,我们就选第二条吧,点击【确定】按钮 

     

    这时的"入库信息"窗口中就填写上了刚才选择商品的信息,然后只要在填写上入库数量,点击【确定】就完成了入库操作了,如图:

     出库的思路和入库一样,也是先选择出库单,然后填写出库单信息并保存订单,然后再给订单上添加商品,过程也是通过选择实现,由于类同,就不赘述了...

     然后是库存明细模块,上图:

     

    该模块主要实现的功能是对存放在各个仓库中的商品进行清点,点击商品的行头就显示出该商品的信息:编号、数量、盘点日期、存放仓库;填写好盘点的数量之后单击【保存】按钮,实现保存盘点数据,这个模块也没什么难点,唯一复杂点的就是因为同样的货品可以存放到不同的仓库中,所以点击时要搜索出该商品所在的所有仓库编号,并在“存放仓库”列表中显示。

    最后是库存警报模块,上图:

     

     该模块主要来设置库存上限和库存下限,实现当库存中存放的商品的数量超过库存上限或者低于库存下限时,弹出警告框提醒。

     这样,我们就简单的把项目的功能叙述了下,当然还有一些细节的功能,这里就不再罗列了.....

    代码:

    由于代码端模块较多,我们就按照程序执行调用的层次关系来罗列.这样相对来说看起来思路比较清晰......Model层只是定义了需要用到的实体而已,不再赘述了.....

    1>.Insigma.PSI.IBLLService层

     

     可以看到有很多的功能类,无法全部讲解,所以就挑选一块,后面的模块层中也着重讲解挑选的这一块,我挑选了库存管理模块,即IStoreManageBLLService,贴上该类的代码:

    IStoreManageBLLService

    复制代码
     1 using Insigma.PSI.Model;
     2 using System.ServiceModel;
     3 
     4 namespace Insigma.PSI.IBLLService
     5 {
     6     [ServiceContract]
     7     public interface IStoreManageBLLService
     8     {
     9         [OperationContract]
    10         //获取所有仓库
    11         List<StoreHouse> GetStores(string sqlWhere);
    12 
    13         [OperationContract]
    14         //获取所有仓库编号
    15         List<string> GetAllStoreCode();
    16 
    17         [OperationContract]
    18         //添加仓库
    19         bool AddStore(StoreHouse store);
    20 
    21         [OperationContract]
    22         //修改仓库
    23         bool UpdateStore(StoreHouse store);
    24 
    25         [OperationContract]
    26         //删除仓库
    27         bool DeleteStore(string code);
    28 
    29         [OperationContract]
    30         //修改库存明细
    31         bool UpdateStoreDetails(GoodsDetailsModel goodDetail);
    32 
    33         [OperationContract]
    34         //获取商品明细
    35         List<StoreDetailsModel> GetStoreDetails(string sqlWhere);
    36 
    37         [OperationContract]
    38         //修改商品数量
    39         bool UpdateGoodNum(StoreDetailsModel storeDetail);
    40     }
    41 }

    由于我们要用到WCF来发布服务,所以这里的每个方法都添加了WCF特性,主要功能是获取仓库、获取仓库编号、对仓库的增、删、改、查;由于出库入库对商品的数量有影响,又由于不存在同一张表格中,所以我们专门定义了一个方法来实现修改商品数量;然后出库入库对应一张库存明细表,执行操作之后要修改该表,记录信息,同时也可以获取该表信息,定义的方法就那么多了.....

    2>Insigma.PSI.BLLService

     

    这层是对上面提及的接口层的实现,但除了实现之外,我还在这里加了一个反射机制,在这层按照原来三层的思路是要调用DAL层来实现对数据库的操作,但因为考虑到要适用于不同的数据库,所以我们不知道要调用哪个数据库层的DAL来操作,这就是这个反射存在的意义了,我们可以通过反射来读取配置文件中定义的数据库信息,从而创建对应数据库类的实例来操作....先贴上StoreManageBLLService的代码,之后再接着讲解,看到了代码思路会清晰点: 

    StoreManageBLLService
    1 using Insigma.PSI.Model;
      2 using Insigma.PSI.IBLLService;
      3 using Insigma.PSI.IDAL;
      4 using Insigma.PSI.DBFactory;
      5 
      6 namespace Insigma.PSI.BLL
      7 {
      8     public class StoreManageBLLService:IStoreManageBLLService
      9     {
     10         //通过反射获取对应的抽象产品
     11         private IStoreManageDAL Ismd = Refection.GetFactory().StoreManageProduct;
     12 
     13         /// <summary>
     14         /// 获取StoresHost表数据
     15         /// </summary>
     16         /// <param name="sqlWhere"></param>
     17         /// <returns></returns>
     18         public List<StoreHouse> GetStores(string sqlWhere)
     19         {
     20             return Ismd.GetStores(sqlWhere);
     21         }
     22 
     23         /// <summary>
     24         /// 添加仓库
     25         /// </summary>
     26         /// <param name="store"></param>
     27         /// <returns></returns>
     28         public bool AddStore(StoreHouse store)
     29         {
     30             int result = Ismd.AddStore(store);
     31             if (result > 0)
     32             {
     33                 return true;
     34             }
     35             else
     36             {
     37                 return false;
     38             }
     39         }
     40 
     41         /// <summary>
     42         /// 修改仓库
     43         /// </summary>
     44         /// <param name="store"></param>
     45         /// <returns></returns>
     46         public bool UpdateStore(StoreHouse store)
     47         {
     48             int result = Ismd.UpdateStore(store);
     49 
     50             if (result > 0)
     51             {
     52                 return true;
     53             }
     54             else
     55             {
     56                 return false;
     57             }
     58         }
     59 
     60         /// <summary>
     61         /// 删除仓库
     62         /// </summary>
     63         /// <param name="code"></param>
     64         /// <returns></returns>
     65         public bool DeleteStore(string code)
     66         {
     67             int result = Ismd.DeleteStore(code);
     68 
     69             if (result > 0)
     70             {
     71                 return true;
     72             }
     73             else
     74             {
     75                 return false;
     76             }
     77         }
     78 
     79         /// <summary>
     80         /// 获取所有仓库编号
     81         /// </summary>
     82         /// <returns></returns>
     83         public List<string> GetAllStoreCode()
     84         {
     85             return Ismd.GetAllStoreCode();
     86         }
     87 
     88         /// <summary>
     89         /// 修改商品明细的数量信息
     90         /// </summary>
     91         /// <param name="goodDetail"></param>
     92         /// <returns></returns>
     93         public bool UpdateStoreDetails(GoodsDetailsModel goodDetail)
     94         {
     95             int result = Ismd.UpdateStoreDetails(goodDetail);
     96 
     97             if (result > 0)
     98             {
     99                 return true;
    100             }
    101             else
    102             {
    103                 return false;
    104             }
    105         }
    106 
    107         /// <summary>
    108         /// 获取所有库存明细
    109         /// </summary>
    110         /// <param name="sqlWhere"></param>
    111         /// <returns></returns>
    112         public List<StoreDetailsModel> GetStoreDetails(string sqlWhere)
    113         {
    114             return Ismd.GetStoreDetails(sqlWhere);
    115         }
    116 
    117         /// <summary>
    118         /// 修改库存明细的盘点数量
    119         /// </summary>
    120         /// <param name="storeDetail"></param>
    121         /// <returns></returns>
    122         public bool UpdateGoodNum(StoreDetailsModel storeDetail)
    123         {
    124             int result = Ismd.UpdateGoodNum(storeDetail);
    125 
    126             if (result > 0)
    127             {
    128                 return true;
    129             }
    130             else
    131             {
    132                 return false;
    133             }
    134         }
    135     }
    136 } 

    从代码中可以看到我们是通过反射来获取DAL的实例的,然后再调用该实例的方法,那么反射里是怎么实现的呢?贴上代码:

    反射
     1 using System.Configuration;
     2 using System.Reflection;
     3 using Insigma.PSI.DBFactory;
     4 
     5 namespace Insigma.PSI.BLL
     6 {
     7     public class Refection
     8     {
     9         //定义一个抽象工厂类的对象实例 用于保存作用
    10         private static AbstractFactory DataAccess = null;
    11 
    12         //获取配置文件中定义的数据库信息
    13         private static string path = ConfigurationManager.AppSettings["DllName"];
    14         private static string className = ConfigurationManager.AppSettings["ClassName"];
    15 
    16         //单例模式-----因为每次加载该程序集都会去调用相同的DAL 
    17         //             如果已经加载过了 就不要再次加载 提高性能
    18         static Refection()
    19         { 
    20             //反射----因为不确定要获取什么类型的DAL 不知道是Oracle还是SQL等等 所以这里添加一个反射机制
    21             string _classname = path + "." + className;
    22            DataAccess = (AbstractFactory)Assembly.Load(path).CreateInstance(_classname);
    23         }
    24 
    25         //获取对应数据库的具体工厂
    26         public static AbstractFactory GetFactory()
    27         {
    28             return DataAccess;
    29         }
    30     }
    31 }

    从代码可知,我们获取了配置文件中定义的程序集以及数据库类的信息,通过加载该程序集来获取该数据库类的实例,同时,添加了单例模式,因为考虑到每次加载该类库的时候都要来获取一次数据库类的实例,但是该数据库类只要配置文件定义不变他就不会变,所以不用每次都去创建实例 ,只需要创建一次就可以了,提高性能,所以就是单例模式的作用了,这里首先定义了一个AbstractFactory类型(后面会讲到)变量来接受创建好的实例,该变量也是static类型的,保证唯一性,我这里是将构造函数改为static的方式,然后在静态构造函数中实例化数据库类,并赋值给定义好的变量,因为静态构造函数只会执行一次,之后就不会执行了,这就保证了只实例一次,然后定义一个GetFactory()方法来返回数据库实例,这样就达到了"单例"的效果了,当然单例模式还有一种思路是将构造函数设为private,也同样定义一个静态变量和静态方法来创建实例,同样保证了"单例"。

    然后看看配置文件中定义的数据库信息:

    web.config
    1 <configuration>
    2   <!--定义数据库信息-->
    3   <appSettings>
    4     <!--程序集名称-->
    5     <add key="DLLName" value="Insigma.PSI.OracleDAL"/>
    6     <!--数据库类名-->
    7     <add key="ClassName" value="OracleFactory"/>
    8   </appSettings>

    可以看到配置文件中定义了程序集的名称,数据库类的名称,但其实这个数据库类就是工厂类的名称。反射中提到了AbstractFactory类型,这是抽象工厂模块中的内容,那么为什么要有这个抽象工厂呢??存在的意义是什么呢?我们就来看看抽象工厂,我的思路:定义一个抽象工厂,里面是一些抽象产品,对应于IDAL中定义的类型的产品,然后在每个数据库类库中定义一个具体工厂,该具体工厂继承抽象工厂,重写抽象产品,返回具体产品,即对IDAL接口类的实现类(DAL)的对应实例,那你会想到了,如没有工厂我们照样可以实现用反射类获取实例的呀,但你想想这时候获取到得实例是什么?它就是我们工厂类中的单个产品而已,当我们的产品有很多的时候怎么办呢,一个DAL类库中的每个类都是一个产品,那难道我们把每个产品都在配置文件中去定义,然后用到的时候通过反射去获取么??显然不可能,所以我们加了抽象工厂模式了,在DAL类库中有一个具体的工厂类,我们所有的产品都由该工厂来创建,那我们获取的是时候只需要获取工厂实例,然后通过该实例来创建我们需要的产品就可以了...... 

    3>Insigma.PSI.IDAL层

     

    同样的拿IStoreManageDAL类讲解,上代码:

    IStoreManageDAL
    1 using Insigma.PSI.Model;
     2 
     3 namespace Insigma.PSI.IDAL
     4 {
     5     public interface IStoreManageDAL
     6     {
     7         List<StoreHouse> GetStores(string sqlWhere);
     8         List<string> GetAllStoreCode();
     9         int AddStore(StoreHouse store);
    10         int UpdateStore(StoreHouse store);
    11         int DeleteStore(string code);
    12         int UpdateStoreDetails(GoodsDetailsModel goodDetail);
    13         List<StoreDetailsModel> GetStoreDetails(string sqlWhere);
    14         int UpdateGoodNum(StoreDetailsModel storeDetail);
    15     }
    16 }

    这也是一个接口类,接口的作用就是规范行为,定义一种契约,继承该接口的类都必须实现契约,所以这里主要来约束DAL实现层的行为

    4>.Insigma.PSI.DBFactory 

     

    抽象工厂模块中就一个抽象工厂类,就直接贴上类代码:

    AbstractFactory
    1 using Insigma.PSI.IDAL;
     2 
     3 namespace Insigma.PSI.DBFactory
     4 {
     5     //定义一个抽象工厂 便于适用于不同的数据库  每个数据库都可以建立一个具体工厂 继承该工厂 
     6     public abstract class AbstractFactory
     7     {
     8        //抽象产品类---对应于IDAL层
     9        public abstract ISysUserDAL SysUserProduct { get; }
    10        public abstract IStoreManageDAL StoreManageProduct { get;}
    11        public abstract IDepartmentDAL DepartmentProduct { get; }
    12        public abstract IHandleGeneralsDAL HandleGeneralsProduct { get; }
    13        public abstract IGoodsDAL GoodsProduct { get; }
    14        public abstract IHandle_GoodDetailsDAL Handle_GoodDetailsProduct { get; }
    15        public abstract IStaffsDAL StaffsProduct { get; }
    16        public abstract ICompanyDAL CompanyProduct { get; }
    17     }
    18 }

    在抽象类中为每个在IDAL中定义的类型都对应的建立了一个属性(也可以定义成方法),因为加了抽象工厂之后,IDAL中的每个类都是一个抽象产品类,是产品类的基类,而DAL中的每个类都是该基类的派生类,都实现了基类中定义的方法,最终返回的具体产品的类型都为抽象产品类型(子类赋值给基类)。

    5>.Insigma.PSI.OracleDAL

      

    有一个工厂类,用于创建具体产品实例,贴上工厂类代码:

    Oracle工厂
    1 using Insigma.PSI.DBFactory;
      2 using System.Web;
      3 using Insigma.PSI.IDAL;
      4 
      5 namespace Insigma.PSI.OracleDAL
      6 {
      7     //具体工厂:Oracle
      8     public class OracleFactory:AbstractFactory
      9     {
     10         //定义DAL类型变量,用于保存
     11         private SysUserDAL sud = null;
     12         private DepartmentDAL dp = null;
     13         private StoreManageDAL sm = null;
     14         private HandleGeneralsDAL hg = null;
     15         private GoodsDAL gd = null;
     16         private Handle_GoodDetailsDAL h_g = null;
     17         private StaffsDAL sd = null;
     18         private CompanyDAL cd = null;
     19 
     20 
     21         //具体产品:SysUserDAL
     22         public override ISysUserDAL SysUserProduct
     23         {
     24             get 
     25             {
     26                 //首先搜索缓存 看看是否有对应的产品
     27                 if (HttpRuntime.Cache.Get("sysuserdal") == null)
     28                 {
     29                     sud = new SysUserDAL();
     30                     //添加缓存机制-----将sud添加到缓存 因为每个用户调用都会去实例化同一个对象 加入缓存机制 
     31                     //                 如果要获取相同类型的对象 则可以直接从缓存中获取 提高性能
     32                     HttpRuntime.Cache.Insert("sysuserdal", sud,null,DateTime.Now.AddMinutes(5),TimeSpan.Zero);
     33                 }
     34                 
     35                 //返回存储在缓存中的值
     36                 return (SysUserDAL)HttpRuntime.Cache.Get("sysuserdal");
     37             }
     38         }
     39 
     40         //具体产品:DepartmentDAL
     41         public override IDepartmentDAL DepartmentProduct
     42         {
     43             get
     44             {
     45                 //首先搜索缓存 看看是否有对应的产品
     46                 if (HttpRuntime.Cache.Get("departmentdal") == null)
     47                 {
     48                     dp = new DepartmentDAL();
     49                     //添加缓存机制-----将sud添加到缓存 因为每个用户调用都会去实例化同一个对象 加入缓存机制 
     50                     //                 如果要获取相同类型的对象 则可以直接从缓存中获取 提高性能
     51                     HttpRuntime.Cache.Insert("departmentdal", dp, null, DateTime.Now.AddMinutes(5), TimeSpan.Zero);
     52                 }
     53 
     54                 //返回存储在缓存中的值
     55                 return (DepartmentDAL)HttpRuntime.Cache.Get("departmentdal");
     56 
     57             }
     58         }
     59 
     60         //具体产品:StoreManageDAL
     61         public override IStoreManageDAL StoreManageProduct
     62         {
     63             get 
     64             {
     65                 //首先搜索缓存 看看是否有对应的产品
     66                 if (HttpRuntime.Cache.Get("storemanagedal") == null)
     67                 {
     68                     sm = new StoreManageDAL();
     69                     //添加缓存机制-----将sud添加到缓存 因为每个用户调用都会去实例化同一个对象 加入缓存机制 
     70                     //                 如果要获取相同类型的对象 则可以直接从缓存中获取 提高性能
     71                     HttpRuntime.Cache.Insert("storemanagedal", sm, null, DateTime.Now.AddMinutes(5), TimeSpan.Zero);
     72                 }
     73 
     74                 //返回存储在缓存中的值
     75                 return (StoreManageDAL)HttpRuntime.Cache.Get("storemanagedal");
     76             }
     77         }
     78 
     79         //具体产品:HandleGeneralsDAL
     80         public override IHandleGeneralsDAL HandleGeneralsProduct
     81         {
     82             get 
     83             {
     84                 if(HttpRuntime.Cache.Get("handlegenerals")==null)
     85                 {
     86                     hg = new HandleGeneralsDAL();
     87                     HttpRuntime.Cache.Insert("handlegenerals", hg);
     88                 }
     89                 return (HandleGeneralsDAL)HttpRuntime.Cache.Get("handlegenerals");
     90             }
     91         }
     92 
     93         //具体产品:GoodsDAL 
     94         public override IGoodsDAL GoodsProduct
     95         {
     96             get 
     97             {
     98                 if (HttpRuntime.Cache.Get("good") == null)
     99                 {
    100                     gd = new GoodsDAL();
    101                     HttpRuntime.Cache.Insert("good", gd);
    102                 }
    103                 return (GoodsDAL)HttpRuntime.Cache.Get("good");
    104             }
    105         }
    106 
    107         //具体产品:Handle_GoodDetailsDAL
    108         public override IHandle_GoodDetailsDAL Handle_GoodDetailsProduct
    109         {
    110             get
    111             {
    112                 if (HttpRuntime.Cache.Get("hand_good") == null)
    113                 {
    114                     h_g = new Handle_GoodDetailsDAL();
    115                     HttpRuntime.Cache.Insert("hand_good", h_g);
    116                 }
    117                 return (Handle_GoodDetailsDAL)HttpRuntime.Cache.Get("hand_good");
    118             }
    119         }
    120 
    121         //具体产品:StaffsDAL
    122         public override IStaffsDAL StaffsProduct
    123         {
    124             get 
    125             {
    126                 if (HttpRuntime.Cache.Get("staff") == null)
    127                 {
    128                     sd = new StaffsDAL();
    129                     HttpRuntime.Cache.Insert("staff", sd);
    130                 }
    131                 return (StaffsDAL)HttpRuntime.Cache.Get("staff");
    132             }
    133         }
    134 
    135         //具体产品:CompanyDAL
    136         public override ICompanyDAL CompanyProduct
    137         {
    138             get
    139             {
    140                 if (HttpRuntime.Cache.Get("company") == null)
    141                 {
    142                     cd = new CompanyDAL();
    143                     HttpRuntime.Cache.Insert("company", cd);
    144                 }
    145                 return (CompanyDAL)HttpRuntime.Cache.Get("company");
    146             }
    147         }
    148 
    149     }
    150 }

    在创建具体产品实例的时候我们还用到了缓存机制,每次使用产品功能的时候都回去实例化一个具体的产品返回,所以多次使用同一产品的时候就做了很多无谓的实例化,所以我加了一层缓存,用来将产品的实例缓存起来,下次再需要该产品时直接从缓存中读取就可以了,提高了性能。

    我这里用的是Runtime.Cache.Get()来获取存,Runtime.Cache.Insert()来添加缓存。

    当然还有一种方法是用HttpContext.Current.Cache.Get()来取,HttpContext.Current.Cache.Insert()来添加缓存。

    至于这两者的区别,要涉及到asp.net生命周期和其他方面的一些内容了,这里就不解析了..... 

    SqlDAL中的内容和Oracle类似,也是建立了一个工厂创建具体产品,同样继承并实现了IDAL中定义的方法,这里也不罗列了...... 

    到这里抽象工厂的角色都出现了,那么来总结下:

    抽象工厂:AbstractFactory类

    抽象产品:IDAL类库中每个类

    具体工厂:1.OracleFactory  2.SqlFactory

    具体产品:DAL层中定义的每个类 

    6>.WCF

    我们仍然拿StoreManageBLL.svc来讲解,贴上代码:

    StoreManageBLLService

    <%@ ServiceHost Language="C#" Debug="true" Service="Insigma.PSI.BLL.StoreManageBLLService" %>

     定义了程序集的名称和服务类名,然后在web.config中配置服信息,上代码:

    web.config
    <system.web>
        <compilation debug="true" targetFramework="4.0" />
      </system.web>
      <system.serviceModel>
        <behaviors>
          <serviceBehaviors>
            <behavior>
              <!-- 为避免泄漏元数据信息,请在部署前将以下值设置为 false 并删除上面的元数据终结点 -->
              <serviceMetadata httpGetEnabled="true"/>
              <!-- 要接收故障异常详细信息以进行调试,请将以下值设置为 true。在部署前设置为 false 以避免泄漏异常信息 -->
              <serviceDebug includeExceptionDetailInFaults="true"/>
            </behavior>
          </serviceBehaviors>
        </behaviors>
        <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
      </system.serviceModel>
      <system.webServer>
        <modules runAllManagedModulesForAllRequests="true"/>
      </system.webServer>

    7>.Insigma.PSI.UI 

    服务配置好了,那我们客户端怎么调用呢??所以我们需要在客户端的app.config配置文件中添加终结点信息,上代码:

    app.config
     1 <configuration>
     2     <system.serviceModel>
     3         <client>
     4             <endpoint address="http://localhost:33864/WcfWebRelease/SysUserBLL.svc"
     5                 binding="basicHttpBinding" bindingConfiguration="" contract="Insigma.PSI.IBLLService.ISysUserBLLSerivce"
     6                 name="SysUserService" />
     7             <endpoint address="http://localhost:33864/WcfWebRelease/DepartmentBLL.svc"
     8                 binding="basicHttpBinding" bindingConfiguration="" contract="Insigma.PSI.IBLLService.IDepartmentBLLService"
     9                 name="DepartmentBLLService" />
    10             <endpoint address="http://localhost:33864/WcfWebRelease/StoreManageBLL.svc"
    11                 binding="basicHttpBinding" bindingConfiguration="" contract="Insigma.PSI.IBLLService.IStoreManageBLLService"
    12                 name="StoreManageBLLService" />
    13           <endpoint address="http://localhost:33864/WcfWebRelease/HandleGeneralsBLL.svc"
    14                binding="basicHttpBinding" bindingConfiguration="" contract="Insigma.PSI.IBLLService.IHandleGeneralsBLLService"
    15                name="HandleGeneralsBLLService" />
    16           <endpoint address="http://localhost:33864/WcfWebRelease/GoodsBLL.svc"
    17               binding="basicHttpBinding" bindingConfiguration="" contract="Insigma.PSI.IBLLService.IGoodsBLLService"
    18               name="GoodsBLLService" />
    19           <endpoint address="http://localhost:33864/WcfWebRelease/Handle_GoodDetails.svc"
    20              binding="basicHttpBinding" bindingConfiguration="" contract="Insigma.PSI.IBLLService.IHandle_GoodDetailsBLLService"
    21              name="Handle_GoodDetailsBLLService" />
    22           <endpoint address="http://localhost:33864/WcfWebRelease/StaffsBLL.svc"
    23              binding="basicHttpBinding" bindingConfiguration="" contract="Insigma.PSI.IBLLService.IStaffsBLLService"
    24              name="StaffsBLLService" />
    25           <endpoint address="http://localhost:33864/WcfWebRelease/CompanyBLL.svc"
    26              binding="basicHttpBinding" bindingConfiguration="" contract="Insigma.PSI.IBLLService.ICompanyBLLService"
    27              name="CompanyBLLService" />
    28         </client>
    29     </system.serviceModel>  

    同时,我在客户端专门定义了一个类用来创建wcf代理,返回BLL实例,上代码:

    代理类
     1 namespace Insigma.PSI.UI
      2 {
      3     public class GetServiceFromWcf
      4     {
      5 
      6         private static ISysUserBLLSerivce _SysUserBLLSerivceProxy;
      7         private static IDepartmentBLLService _DepartmentBLLService;
      8         private static IStoreManageBLLService _StoreManageBLLService;
      9         private static IHandleGeneralsBLLService _HandleGeneralsBLLService;
     10         private static IGoodsBLLService _GoodsBLLService;
     11         private static IHandle_GoodDetailsBLLService _Handle_GoodDetailsBLLService;
     12         private static IStaffsBLLService _StaffsBLLService;
     13         private static ICompanyBLLService _CompanyBLLService;
     14 
     15 
     16         //获取SysUser代理
     17         public static ISysUserBLLSerivce GetSysUserBLLSerivceProxy()
     18         {
     19             if (_SysUserBLLSerivceProxy == null)
     20             {
     21                 ChannelFactory<ISysUserBLLSerivce> channelFactory = new ChannelFactory<ISysUserBLLSerivce>("SysUserService");
     22                 _SysUserBLLSerivceProxy = channelFactory.CreateChannel();
     23             }
     24             return _SysUserBLLSerivceProxy;
     25         }
     26 
     27         //获取Department代理
     28         public static IDepartmentBLLService GetDepartmentBLLServiceProxy()
     29         {
     30             if (_DepartmentBLLService == null)
     31             {
     32                 ChannelFactory<IDepartmentBLLService> channelFactory = new ChannelFactory<IDepartmentBLLService>("DepartmentBLLService");
     33                 _DepartmentBLLService = channelFactory.CreateChannel();
     34             }
     35             return _DepartmentBLLService;
     36         }
     37 
     38         //获取StoreHost代理
     39         public static IStoreManageBLLService GetStoreManageBLLServiceProxy()
     40         {
     41             if (_StoreManageBLLService == null)
     42             {
     43                 ChannelFactory<IStoreManageBLLService> channelFactory = new ChannelFactory<IStoreManageBLLService>("StoreManageBLLService");
     44                 _StoreManageBLLService = channelFactory.CreateChannel();
     45             }
     46             return _StoreManageBLLService;
     47         }
     48 
     49         //获取HandleGenerals代理
     50         public static IHandleGeneralsBLLService GetHandleGeneralsBLLServiceProxy()
     51         {
     52             if (_HandleGeneralsBLLService == null)
     53             {
     54                 ChannelFactory<IHandleGeneralsBLLService> channelFactory = new ChannelFactory<IHandleGeneralsBLLService>("HandleGeneralsBLLService");
     55                 _HandleGeneralsBLLService = channelFactory.CreateChannel();
     56             }
     57             return _HandleGeneralsBLLService;
     58         }
     59 
     60         //获取Goods代理
     61         public static IGoodsBLLService GetGoodsBLLService()
     62         {
     63             if (_GoodsBLLService == null)
     64             {
     65                 ChannelFactory<IGoodsBLLService> channelFactory = new ChannelFactory<IGoodsBLLService>("GoodsBLLService");
     66                 _GoodsBLLService = channelFactory.CreateChannel();
     67             }
     68             return _GoodsBLLService;
     69         }
     70 
     71         //获取Handle_GoodDetails代理
     72         public static IHandle_GoodDetailsBLLService GetHandle_GoodDetails()
     73         {
     74             if (_Handle_GoodDetailsBLLService == null)
     75             {
     76                 ChannelFactory<IHandle_GoodDetailsBLLService> channelFactory = new ChannelFactory<IHandle_GoodDetailsBLLService>("Handle_GoodDetailsBLLService");
     77                 _Handle_GoodDetailsBLLService = channelFactory.CreateChannel();
     78             }
     79             return _Handle_GoodDetailsBLLService;
     80         }
     81 
     82         //获取Staffs代理
     83         public static IStaffsBLLService GetStaffsBLLService()
     84         {
     85             if (_StaffsBLLService == null)
     86             {
     87                 ChannelFactory<IStaffsBLLService> channelFactory = new ChannelFactory<IStaffsBLLService>("StaffsBLLService");
     88                 _StaffsBLLService = channelFactory.CreateChannel();
     89             }
     90             return _StaffsBLLService;
     91         }
     92 
     93         ///获取Company代理
     94         public static ICompanyBLLService GetCompanyBLLService()
     95         {
     96             if (_CompanyBLLService == null)
     97             {
     98                 ChannelFactory<ICompanyBLLService> channelFactory = new ChannelFactory<ICompanyBLLService>("CompanyBLLService");
     99                 _CompanyBLLService = channelFactory.CreateChannel();
    100             }
    101             return _CompanyBLLService;
    102         }
    103     }
    104 }

    Utility没什么好讲的,就是两个数据库操作类,一个Oracle类,一个SQL类,这里就不贴图贴代码了.... 

    疑问解答 

    架构、项目、代码端都讲解完成了....接下来和大家分享项目中碰到的一个绑定的问题....

    首先贴上要绑定的Model层信息:

    外键对象
     1 namespace Insigma.PSI.Model
     2 {
     3     [DataContract]
     4     public class Handles_GoodDetailsModel
     5     {
     6         //外键对象
     7         [DataMember]
     8         public HandelGeneralsModel Handles;
     9 
    10         [DataMember]
    11         public GoodsDetailsModel GoodsDetails;
    12     }
    13 }

    讲讲要求吧,就是希望当页面载入是显示订单表_商品详细表的综合信息,由于是不同的表,所以我在Model层建立了一个单独的Model类,里面是一对外键对象,因为存在主外键的关系,所以我就考虑到了用外键对象来存放数据,然后通过外键建立两张表的视图,然后获取视图数据,OK,获取完全没有问题,获取到了就是页面端的绑定了,按照原来的思路,上代码:

    错误绑定
    1             //【错误】绑定
    2             List<Handles_GoodDetailsModel> hand_goodList = GetServiceFromWcf.GetHandle_GoodDetails().GetHandle_GoodDetails(sqlWhere);
    3             dgv_DetailShow.DataSource = hand_goodList;

     结果就是,始终绑不上,经过深思熟虑之后,才觉得应该是外界对象的问题,所以收集资料,终于发现错误点确实在外键对象上,外键对象无法直接直接绑定上去,至少DataGridView无法直接绑定,web中的Eval()、Bind()可以绑定外键对象(经测试)........好了,问题找到了就要开始解决了,最后终于发现了一种手动绑定的方法,上代码:

    正确绑定
    1             //【正确】手工绑定
     2             List<Handles_GoodDetailsModel> hand_goodList = GetServiceFromWcf.GetHandle_GoodDetails().GetHandle_GoodDetails(sqlWhere);
     3             //由于存在外键对象  无法直接绑定 需要手工绑定
     4             dgv_DetailShow.Rows.Clear();
     5             foreach (Handles_GoodDetailsModel model in hand_goodList)
     6             {
     7                 //新增一行,该值会随着循环绑定自增
     8                 int i = dgv_DetailShow.Rows.Add();
     9 
    10                 //给对应行绑定数据
    11                 dgv_DetailShow.Rows[i].Cells["HandCode"].Value = model.Handles.HandCode;
    12                 dgv_DetailShow.Rows[i].Cells["ContCode"].Value = model.Handles.ContCode;
    13                 dgv_DetailShow.Rows[i].Cells["HandDate"].Value = model.Handles.HandDate;
    14                 dgv_DetailShow.Rows[i].Cells["StaffCode"].Value = model.Handles.StaffCode;
    15                 dgv_DetailShow.Rows[i].Cells["StoreDate"].Value = model.Handles.StoreDate;
    16 
    17                 dgv_DetailShow.Rows[i].Cells["DetailCode"].Value = model.GoodsDetails.DetailCode;
    18                 dgv_DetailShow.Rows[i].Cells["GooCode"].Value = model.GoodsDetails.GooCode;
    19                 dgv_DetailShow.Rows[i].Cells["GooNum"].Value = model.GoodsDetails.GooNum;
    20                 dgv_DetailShow.Rows[i].Cells["GooPrice"].Value = model.GoodsDetails.GooPrice;
    21                 dgv_DetailShow.Rows[i].Cells["StoreCodeIn"].Value = model.GoodsDetails.StoreCodeIn;
    22                 dgv_DetailShow.Rows[i].Cells["StoreCodeOut"].Value = model.GoodsDetails.StoreCodeOut;
    23             }
    24         }

     至此,,本篇博客就算告一个段落了,欢迎大家评点指导。。。。。。。

     
    分类: 架构思想
  • 相关阅读:
    听豆瓣架构变迁分享会总结
    业界对生成图片缩略图的做法归纳
    58和百姓网的技术学习
    减少存储过程封装业务逻辑-web开发与传统软件开发的思维模式不同
    网站速度问题排查与定位经验
    调度思想-现实中的事物与技术里面其实存在类似道理
    关于图片或者文件在数据库的存储方式归纳
    mysql单表体积和一个库设计多少张表为妥
    php的变量引用与销毁机制
    选择技术方案权衡时,考虑对其可控性很重要
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2665055.html
Copyright © 2011-2022 走看看