|
系列文章導航:
WCF版的PetShop之三:實現分布式的Membership和上下文傳遞
上一篇文章主要討論的是PetShop的模塊劃分,在這一篇文章中我們來討論在一個模塊中如何進行層次劃分。模塊劃分應該是基于功能的,一個模塊可以看成是服務于某項功能的所有資源的集合;層次劃分側重于關注點分離(SoC:Separation of Concern ),讓某一層專注于某項單一的操作,以實現重用性、可維護性、可測試性等相應的目的。Source Code從這里下載。
一、基本的層次結構
我們接下來將目光聚焦到模塊內部,看看每一個模塊具體又有怎樣的層次劃分。我們將Infrastructures、Products和Orders目標展開,將會呈現出如圖1所示的層次結構。
圖1 從解決方案的結構看模塊的層次結構
以Products模塊為例,它由如下的項目組成:
- Products:對于整個應用來說,Products是最終基于該模塊功能的提供者;
- Products.Interface: 模塊提供給其他模塊的服務接口,本項目被Products項目引用;
- Products.Service.Interface:模塊客戶端和服務端進行服務調用的WCF服務契約,Products項目最為WCF服務的客戶端通過該接口進行服務調用;
- Products.Service:實現了上述服務契約的WCF服務,引用了Products.Service.Interface項目;
- Products.BusinessComponent:也可以稱為業務邏輯層,實現了真正的業務邏輯;
- Products.DataAccess:數據訪問層,在這里主要提供對數據庫的訪問;
- Products.BusinessEntity:提供的業務實體(BusinessEntity)類型的定義。一般來講,業務實體和數據契約(DataContract)是不同的,前者主要對本模塊,后者則對外,在這里為了簡單起見,將兩者合二為一。
從部署的角度講,Products和Products.Interface部署與于Web服務器;Products.Service、Products.BusinessComponent和Products.DataAccess則部署于應用服務器;Products.Service.Interface和Products.BusinessEntity則同時被部署于Web服務器和應用服務器。整個層次結構大體上如圖2所示。
圖2 邏輯層次和物理部署
二、數據庫設計
整個應用主要涉及4個表,其中3個用于存儲業務數據(產品表、訂單表和訂單明細表),另一個用于存儲簡單的審核信息(審核表)。4個表的結構可以分別參考相應的SQL腳本。
產品表(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]
系列文章導航:
WCF版的PetShop之三:實現分布式的Membership和上下文傳遞
四、數據訪問層設計
數據訪問層定義在{Module}.DataAccess中,它完成單純的基于數據庫操作。為了便于操作,我寫了一個簡單的幫助類:DbHelper。DbHelper通過ADO.NET完成一些簡單的操作,ExecuteReader、ExecuteNonQuery和ExecuteScalar對應DbCommand的同名方法。此外,該DbHelper與具體的數據庫無關,同時支持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技術:WCF版的PetShop之二:模塊中的層次劃分,轉載需保留來源!
鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。