花了點時間完成了一個進銷存的項目,個人覺得對邏輯分析,架構思想都有一定的體會,故拿出來和大家分享下,首先介紹下項目的功能吧,主要功能有采購管理,銷售管理,庫存管理,人員信息管理,系統管理等,不過寫這篇博客的主要目的並不是講解如何實現項目功能,而是分享下該項目的架構思想、實現步驟和碰到的一些問題,分享下心得體會罷了......
數據庫設計
下面進入主題,首先貼上項目的主界面,由於對界面要求不是很高,所以界面相對來說比較簡單,甚至可是說是簡陋了,,呵呵,不過重點不在界面上,勇敢的直接上圖:
架構:
首先說說項目架構吧,,貼上項目模塊圖:
從圖中可知,項目總共分10個模塊,采用三層架構+WCF+反射+抽象工廠來搭建,其中還加入了單例模式,緩存機制。下面分別說說每個模塊的作用:
Insigma.PSI.UI:WinForm界面層
Insigma.PSI.DBFactory:抽象工廠層,主要為考慮可以使項目可以適用Oracle數據庫和SQL數據庫,就搭建了一個抽象工廠層,分別在Oracle數據庫層和SQL數據庫層建立一個 工 廠來實現該抽象工廠
C:\..\WcfWebRelease\:web層,主要用來發布WCF服務
首先看看庫存列表,上圖:
庫存列表的功能比較簡單,只是實現了倉庫的增、刪、改、查,由於功能比較簡單,也就不多做講解了....
再貼上出庫/入庫模塊圖:
這塊應該算是庫存模塊中的核心模塊了,因為該塊的業務邏輯比較多,比較繁瑣,大致講講業務邏輯吧,大致的邏輯為:出庫單/出庫單-->填寫訂單-->出庫/入庫-->修改庫存信息,按照這個順序來完成入庫出庫,順序不能顛倒,同時還要實現訂單的刪除,修改,在修改庫存信息時由於表和表之間有很多的外鍵關系,所以要同時刪除多張表中含有刪除信息的內容,實現聯級刪除,由於這里考慮到要保證結果的一致性,所以用事務來實現。再看看界面,為了保證用戶按照這個邏輯順序操作,首先我添加了一對單選框(出庫單,入庫單),當單選框都沒有選中時,保存訂單按鈕、出庫、入庫按鈕都是不可用狀態,當用戶選擇了訂單類型之后,保存訂單按鈕轉為可用狀態,需要用戶填寫訂單信息,填寫好對應信息之后保存訂單,保存成功之后列表框中出現剛生產的訂單,同時訂單號是自動來生成的,入庫單是“S_I”開頭,出庫單是"S_O"開頭,后面五位數字為隨機生成,這樣生成的訂單號易於區別,也避免了訂單號的重復,然后根據用戶選擇的訂單類型,對應的按鈕轉為可用(出庫單-->出庫按鈕) ,這樣就保證了用戶始終是按照這個順序來操作,同時訂單列表框下有刪除訂單按鈕,點擊可以刪除選中按鈕。
下面那出庫為例,看看如何實現入庫:
點擊【入庫】按鈕,彈出商品選擇窗口,窗口中顯示了訂單號和倉庫編號,同時還有一個【選擇】按鈕,通過該按鈕選擇商品
點擊【選擇】按鈕,彈出商品列表窗口,由於我這里商品記錄比較少,只有兩條,我們就選第二條吧,點擊【確定】按鈕
這時的"入庫信息"窗口中就填寫上了剛才選擇商品的信息,然后只要在填寫上入庫數量,點擊【確定】就完成了入庫操作了,如圖:
出庫的思路和入庫一樣,也是先選擇出庫單,然后填寫出庫單信息並保存訂單,然后再給訂單上添加商品,過程也是通過選擇實現,由於類同,就不贅述了...
然后是庫存明細模塊,上圖:
該模塊主要實現的功能是對存放在各個倉庫中的商品進行清點,點擊商品的行頭就顯示出該商品的信息:編號、數量、盤點日期、存放倉庫;填寫好盤點的數量之后單擊【保存】按鈕,實現保存盤點數據,這個模塊也沒什么難點,唯一復雜點的就是因為同樣的貨品可以存放到不同的倉庫中,所以點擊時要搜索出該商品所在的所有倉庫編號,並在“存放倉庫”列表中顯示。
最后是庫存警報模塊,上圖:
該模塊主要來設置庫存上限和庫存下限,實現當庫存中存放的商品的數量超過庫存上限或者低於庫存下限時,彈出警告框提醒。
這樣,我們就簡單的把項目的功能敘述了下,當然還有一些細節的功能,這里就不再羅列了.....
代碼:
由於代碼端模塊較多,我們就按照程序執行調用的層次關系來羅列.這樣相對來說看起來思路比較清晰......Model層只是定義了需要用到的實體而已,不再贅述了.....
1>.Insigma.PSI.IBLLService層
可以看到有很多的功能類,無法全部講解,所以就挑選一塊,后面的模塊層中也着重講解挑選的這一塊,我挑選了庫存管理模塊,即IStoreManageBLLService,貼上該類的代碼:

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的代碼,之后再接着講解,看到了代碼思路會清晰點:

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的實例的,然后再調用該實例的方法,那么反射里是怎么實現的呢?貼上代碼:

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,也同樣定義一個靜態變量和靜態方法來創建實例,同樣保證了"單例"。
然后看看配置文件中定義的數據庫信息:

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類講解,上代碼:

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
抽象工廠模塊中就一個抽象工廠類,就直接貼上類代碼:

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


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層中定義的每個類
我們仍然拿StoreManageBLL.svc來講解,貼上代碼:

定義了程序集的名稱和服務類名,然后在web.config中配置服信息,上代碼:

<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配置文件中添加終結點信息,上代碼:

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實例,上代碼:

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層信息:

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,獲取完全沒有問題,獲取到了就是頁面端的綁定了,按照原來的思路,上代碼:

2 List<Handles_GoodDetailsModel> hand_goodList = GetServiceFromWcf.GetHandle_GoodDetails().GetHandle_GoodDetails(sqlWhere);
3 dgv_DetailShow.DataSource = hand_goodList;
結果就是,始終綁不上,經過深思熟慮之后,才覺得應該是外界對象的問題,所以收集資料,終於發現錯誤點確實在外鍵對象上,外鍵對象無法直接直接綁定上去,至少DataGridView無法直接綁定,web中的Eval()、Bind()可以綁定外鍵對象(經測試)........好了,問題找到了就要開始解決了,最后終於發現了一種手動綁定的方法,上代碼:

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 }
至此,,本篇博客就算告一個段落了,歡迎大家評點指導。。。。。。。