|
系列文章導(dǎo)航:
WCF版的PetShop之三:實現(xiàn)分布式的Membership和上下文傳遞
上一篇文章主要討論的是PetShop的模塊劃分,在這一篇文章中我們來討論在一個模塊中如何進行層次劃分。模塊劃分應(yīng)該是基于功能的,一個模塊可以看成是服務(wù)于某項功能的所有資源的集合;層次劃分側(cè)重于關(guān)注點分離(SoC:Separation of Concern ),讓某一層專注于某項單一的操作,以實現(xiàn)重用性、可維護性、可測試性等相應(yīng)的目的。Source Code從這里下載。
一、基本的層次結(jié)構(gòu)
我們接下來將目光聚焦到模塊內(nèi)部,看看每一個模塊具體又有怎樣的層次劃分。我們將Infrastructures、Products和Orders目標展開,將會呈現(xiàn)出如圖1所示的層次結(jié)構(gòu)。
圖1 從解決方案的結(jié)構(gòu)看模塊的層次結(jié)構(gòu)
以Products模塊為例,它由如下的項目組成:
- Products:對于整個應(yīng)用來說,Products是最終基于該模塊功能的提供者;
- Products.Interface: 模塊提供給其他模塊的服務(wù)接口,本項目被Products項目引用;
- Products.Service.Interface:模塊客戶端和服務(wù)端進行服務(wù)調(diào)用的WCF服務(wù)契約,Products項目最為WCF服務(wù)的客戶端通過該接口進行服務(wù)調(diào)用;
- Products.Service:實現(xiàn)了上述服務(wù)契約的WCF服務(wù),引用了Products.Service.Interface項目;
- Products.BusinessComponent:也可以稱為業(yè)務(wù)邏輯層,實現(xiàn)了真正的業(yè)務(wù)邏輯;
- Products.DataAccess:數(shù)據(jù)訪問層,在這里主要提供對數(shù)據(jù)庫的訪問;
- Products.BusinessEntity:提供的業(yè)務(wù)實體(BusinessEntity)類型的定義。一般來講,業(yè)務(wù)實體和數(shù)據(jù)契約(DataContract)是不同的,前者主要對本模塊,后者則對外,在這里為了簡單起見,將兩者合二為一。
從部署的角度講,Products和Products.Interface部署與于Web服務(wù)器;Products.Service、Products.BusinessComponent和Products.DataAccess則部署于應(yīng)用服務(wù)器;Products.Service.Interface和Products.BusinessEntity則同時被部署于Web服務(wù)器和應(yīng)用服務(wù)器。整個層次結(jié)構(gòu)大體上如圖2所示。
圖2 邏輯層次和物理部署
二、數(shù)據(jù)庫設(shè)計
整個應(yīng)用主要涉及4個表,其中3個用于存儲業(yè)務(wù)數(shù)據(jù)(產(chǎn)品表、訂單表和訂單明細表),另一個用于存儲簡單的審核信息(審核表)。4個表的結(jié)構(gòu)可以分別參考相應(yīng)的SQL腳本。
產(chǎn)品表(T_PRODUCT)
1: CREATE TABLE [T_PRODUCT] (
2: [PRODUCT_ID] [VARCHAR](50) NOT NULL,
3: [PRODUCT_CATEGORY] [NVARCHAR](128) NOT NULL,
4: [PRODUCT_NAME] [NVARCHAR](256) NOT NULL,
5: [PRODUCT_PIC] [NVARCHAR](512),
6: [PRODUCT_DESC] [NVARCHAR](800),
7: [PRODUCT_UNIT_PRICE] [DECIMAL](10,2) NOT NULL,
8: [PRODUCT_INVENTORY] [INT] NOT NULL,
9:
10: [VERSION_NO] [TIMESTAMP] NOT NULL,
11: [TRANSACTION_ID] [VARCHAR](50) NOT NULL,
12: [CREATED_BY] [NVARCHAR](256) NOT NULL,
13: [CREATED_TIME] [DATETIME] NOT NULL,
14: [LAST_UPDATED_BY] [NVARCHAR](256) NOT NULL,
15: [LAST_UPDATED_TIME] [DATETIME] NOT NULL
16:
17: CONSTRAINT [C_PRODUCT_PK] PRIMARY KEY CLUSTERED ( [PRODUCT_ID] ASC ) ON [PRIMARY]) ON [PRIMARY]
系列文章導(dǎo)航:
WCF版的PetShop之三:實現(xiàn)分布式的Membership和上下文傳遞
四、數(shù)據(jù)訪問層設(shè)計
數(shù)據(jù)訪問層定義在{Module}.DataAccess中,它完成單純的基于數(shù)據(jù)庫操作。為了便于操作,我寫了一個簡單的幫助類:DbHelper。DbHelper通過ADO.NET完成一些簡單的操作,ExecuteReader、ExecuteNonQuery和ExecuteScalar對應(yīng)DbCommand的同名方法。此外,該DbHelper與具體的數(shù)據(jù)庫無關(guān),同時支持SQL Server和Oracle。
1: using System.Collections.Generic;
2: using System.Configuration;
3: using System.Data;
4: using System.Data.Common;
5: using System.Data.OracleClient;
6: using System.Data.SqlClient;
7: namespace Artech.PetShop.Common
8: {
9: public class DbHelper
10: {
11: private DbProviderFactory _dbProviderFactory;
12: private string _connectionString;
13: private DbConnection CreateConnection()
14: {
15: DbConnection connection = this._dbProviderFactory.CreateConnection();
16: connection.ConnectionString = this._connectionString;
17: return connection;
18: }
19:
20: private void DeriveParameters(DbCommand discoveryCommand)
21: {
22: if (discoveryCommand.CommandType != CommandType.StoredProcedure)
23: {
24: return;
25: }
26:
27: if (this._dbProviderFactory is SqlClientFactory)
28: {
29: SqlCommandBuilder.DeriveParameters
30: ((SqlCommand)discoveryCommand);
31: }
32:
33: if(this._dbProviderFactory is OracleClientFactory)
34: {
35: OracleCommandBuilder.DeriveParameters
36: ((OracleCommand)discoveryCommand);
37: }
38: }
39:
40: private void AssignParameters(DbCommand command, IDictionary<string, object> parameters)
41: {
42: IDictionary<string, object> copiedParams = new Dictionary<string, object>();
43: foreach (var item in parameters)
44: {
45: copiedParams.Add(item.Key.ToLowerInvariant(), item.Value);
46: }
47: foreach (DbParameter parameter in command.Parameters)
48: {
49: if (!copiedParams.ContainsKey(parameter.ParameterName.
50: TrimStart('@').ToLowerInvariant()))
51: {
52: continue;
53: }
54:
55: parameter.Value = copiedParams[parameter.ParameterName.
56: TrimStart('@').ToLowerInvariant()];
57: }
58: }
59:
60: public DbHelper(string connectionStringName)
61: {
62: string providerName = ConfigurationManager.ConnectionStrings
63: [connectionStringName].ProviderName;
64: this._connectionString = ConfigurationManager.ConnectionStrings
65: [connectionStringName].ConnectionString;
66: this._dbProviderFactory = DbProviderFactories.GetFactory(providerName);
67: }
68:
69: public DbDataReader ExecuteReader(string procedureName, IDictionary<string, object> parameters)
70: {
71: DbConnection connection = this.CreateConnection();
72: using (DbCommand command = connection.CreateCommand())
73: {
74: command.CommandText = procedureName;
75: command.CommandType = CommandType.StoredProcedure;
76: connection.Open();
77: this.DeriveParameters(command);
78: this.AssignParameters(command, parameters);
79: return command.ExecuteReader(CommandBehavior.CloseConnection);
80: }
81: }
82:
83: public int ExecuteNonQuery(string procedureName, IDictionary<string, object> parameters)
84: {
85: using (DbConnection connection = this.CreateConnection())
86: {
87: using (DbCommand command = connection.CreateCommand())
88: {
89: command.CommandText = procedureName;
90: command.CommandType = CommandType.StoredProcedure;
91: connection.Open();
92: this.DeriveParameters(command);
93: this.AssignParameters(command, parameters);
94: return command.ExecuteNonQuery();
95: }
96: }
97: }
98:
99: public T ExecuteScalar(string procedureName, IDictionary<string, object> parameters)
100: {
101: using (DbConnection connection = this.CreateConnection())
102: {
103: using (DbCommand command = connection.CreateCommand())
104: {
105: command.CommandText = commandText;
106: command.CommandType = CommandType.StoredProcedure;
107: this.DeriveParameters(command);
108: this.AssignParameters(command, parameters);
109: connection.Open();
110: return (T)command.ExecuteScalar();
111: }
112: }
113: }
114: }
115: }
NET技術(shù):WCF版的PetShop之二:模塊中的層次劃分,轉(zhuǎn)載需保留來源!
鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯(lián)系我們修改或刪除,多謝。