摘要:C# 3.0 ~ 物件導向 多層式架構 Plus+
好幾天沒打文章了= =、
感覺有點怠惰了ˋˊ ..
其實 不是 ...
再寫新的架構 ...
突然發現 原來 SQL 放在 資料存取層 有他的道理在 ...
決定 把之前的架構都打碎ˋˊ
基本上 物件模型 單純就是 物件的模型
不包含任何其他的東西 單純對應資料庫資訊
再來 DAL層 <-->BLL層
這樣做之後 BLL曾 可以作好多事情 ...
例如 LIST的排序 篩選 等等 蠻多的 ...
再來 負責資料庫存取 還有連線字串 都變成 靜態類別
方便存取 不然每次都要NEW ...
附帶一提 ... 為了一個非常特殊的理由 ...我要逼自己 用C# ...感覺比較專業一點ˋˊ+
就像 人家都講中文 你講英文 感覺就是比較猛 ...(沒啦 開玩笑的= =、 是為了要證照考試)
廢話不多說 進入我們的主題 ...
首先是 -靜態類別- 取得連線字串(歸類在 命名空間 DAL)

using System.Web.Configuration; 02
03
04
namespace DAL 05
{ 06
public static class ConnectionString 07
{ 08
private static string _ConnStr; 09
10
public static string ConnStr 11
{ 12
get { return _ConnStr; } 13
} 14
public static string GetConnStr() 15
{ 16
_ConnStr = WebConfigurationManager.ConnectionStrings[0].ConnectionString.ToString(); 17
return _ConnStr; 18
} 19
public static string GetConnStr(int index) 20
{ 21
_ConnStr = WebConfigurationManager.ConnectionStrings[index].ConnectionString.ToString(); 22
return _ConnStr; 23
} 24
public static string GetConnStr(string name) 25
{ 26
_ConnStr = WebConfigurationManager.ConnectionStrings[name].ConnectionString.ToString(); 27
return _ConnStr; 28
} 29
static ConnectionString() 30
{ 31
_ConnStr = WebConfigurationManager.ConnectionStrings[0].ConnectionString.ToString(); 32
} 33
} 34
}
29行 靜態類別的建構函式 有興趣請看靜態建構函式 (C# 程式設計手冊)
其他不再多做解釋 ...
再來 -靜態類別- 負責對資料作存取的(歸類在命名空間DAL)
using System; 002
using System.Data; 003
using System.Data.SqlClient; 004
005
namespace DAL 006
{ 007
public static class DataCommand 008
{ 009
public static bool MSSqlSelectQuery(ref string SqlQuery, out DataTable dt) 010
{ 011
dt = new DataTable(); 012
SqlQuery = SqlQuery.Trim(); 013
if (SqlQuery.Contains("@") || SqlQuery.Contains("'") || SqlQuery.Contains("--")) 014
return false; 015
else if(! SqlQuery.StartsWith("SELECT",true,null)) 016
return false; 017
try 018
{ 019
using (SqlConnection SqlConn = new SqlConnection(ConnectionString.GetConnStr())) 020
{ 021
SqlCommand SqlCmd = new SqlCommand(SqlQuery, SqlConn); 022
SqlConn.Open(); 023
dt.Load(SqlCmd.ExecuteReader()); 024
return true; 025
} 026
} 027
catch (Exception) 028
{ 029
return false; 030
} 031
finally 032
{ 033
SqlQuery = null; 034
} 035
} 036
public static bool MSSqlSelectQuery(ref string SqlQuery, out DataSet ds) 037
{ 038
ds = new DataSet(); 039
SqlQuery = SqlQuery.Trim(); 040
if (SqlQuery.Contains("@") || SqlQuery.Contains("'") || SqlQuery.Contains("--")) 041
return false; 042
else if (!SqlQuery.StartsWith("SELECT", true, null)) 043
return false; 044
try 045
{ 046
using (SqlConnection SqlConn = new SqlConnection(ConnectionString.GetConnStr())) 047
{ 048
SqlCommand SqlCmd = new SqlCommand(SqlQuery, SqlConn); 049
SqlDataAdapter da = new SqlDataAdapter(SqlCmd); 050
da.Fill(ds); 051
return true; 052
} 053
} 054
catch (Exception) 055
{ 056
return false; 057
} 058
finally 059
{ 060
SqlQuery = null; 061
} 062
} 063
public static bool MSSqlSelectQuery(ref string SqlQuery,ref SqlParameter Parameter,out DataTable dt) 064
{ 065
dt = new DataTable(); 066
SqlQuery = SqlQuery.Trim(); 067
if (SqlQuery.Contains("'") || SqlQuery.Contains("--")) 068
return false; 069
else if (!SqlQuery.StartsWith("SELECT", true, null)) 070
return false; 071
try 072
{ 073
using (SqlConnection SqlConn = new SqlConnection(ConnectionString.GetConnStr())) 074
{ 075
SqlCommand SqlCmd = new SqlCommand(SqlQuery, SqlConn); 076
SqlCmd.Parameters.Add(Parameter); 077
SqlConn.Open(); 078
dt.Load(SqlCmd.ExecuteReader()); 079
return true; 080
} 081
} 082
catch (Exception) 083
{ 084
return false; 085
} 086
finally 087
{ 088
SqlQuery = null; 089
Parameter = null; 090
} 091
} 092
public static bool MSSqlSelectQuery(ref string SqlQuery, ref SqlParameter Parameter, out DataSet ds) 093
{ 094
ds = new DataSet(); 095
SqlQuery = SqlQuery.Trim(); 096
if (SqlQuery.Contains("'") || SqlQuery.Contains("--")) 097
return false; 098
else if (!SqlQuery.StartsWith("SELECT", true, null)) 099
return false; 100
try 101
{ 102
using (SqlConnection SqlConn = new SqlConnection(ConnectionString.GetConnStr())) 103
{ 104
SqlCommand SqlCmd = new SqlCommand(SqlQuery, SqlConn); 105
SqlCmd.Parameters.Add(Parameter); 106
SqlDataAdapter da = new SqlDataAdapter(SqlCmd); 107
da.Fill(ds); 108
return true; 109
} 110
} 111
catch (Exception) 112
{ 113
return false; 114
} 115
finally 116
{ 117
SqlQuery = null; 118
Parameter = null; 119
} 120
} 121
public static bool MSSqlSelectQuery(ref string SqlQuery, ref SqlParameter[] Parameters, out DataTable dt) 122
{ 123
dt = new DataTable(); 124
SqlQuery = SqlQuery.Trim(); 125
if (SqlQuery.Contains("'") || SqlQuery.Contains("--")) 126
return false; 127
else if (!SqlQuery.StartsWith("SELECT", true, null)) 128
return false; 129
try 130
{ 131
using (SqlConnection SqlConn = new SqlConnection(ConnectionString.GetConnStr())) 132
{ 133
SqlCommand SqlCmd = new SqlCommand(SqlQuery, SqlConn); 134
SqlCmd.Parameters.AddRange(Parameters); 135
SqlConn.Open(); 136
dt.Load(SqlCmd.ExecuteReader()); 137
return true; 138
} 139
} 140
catch (Exception) 141
{ 142
return false; 143
} 144
finally 145
{ 146
SqlQuery = null; 147
Parameters = null; 148
} 149
} 150
public static bool MSSqlSelectQuery(ref string SqlQuery, ref SqlParameter[] Parameters, out DataSet ds) 151
{ 152
ds = new DataSet(); 153
SqlQuery = SqlQuery.Trim(); 154
if (SqlQuery.Contains("'") || SqlQuery.Contains("--")) 155
return false; 156
else if (!SqlQuery.StartsWith("SELECT", true, null)) 157
return false; 158
try 159
{ 160
using (SqlConnection SqlConn = new SqlConnection(ConnectionString.GetConnStr())) 161
{ 162
SqlCommand SqlCmd = new SqlCommand(SqlQuery, SqlConn); 163
SqlCmd.Parameters.AddRange(Parameters); 164
SqlDataAdapter da = new SqlDataAdapter(SqlCmd); 165
da.Fill(ds); 166
return true; 167
} 168
} 169
catch (Exception) 170
{ 171
return false; 172
} 173
finally 174
{ 175
SqlQuery = null; 176
Parameters = null; 177
} 178
} 179
public static int MSSqlExecuteNonQuery(ref string SqlQuery) 180
{ 181
int result = 0; 182
SqlQuery = SqlQuery.Trim(); 183
if (SqlQuery.Contains("@") || SqlQuery.Contains("'") || SqlQuery.Contains("--")) 184
return result; 185
try 186
{ 187
using (SqlConnection SqlConn = new SqlConnection(ConnectionString.GetConnStr())) 188
{ 189
SqlCommand SqlCmd = new SqlCommand(SqlQuery, SqlConn); 190
SqlConn.Open(); 191
result = SqlCmd.ExecuteNonQuery(); 192
return result; 193
} 194
} 195
catch (SqlException) 196
{ 197
return result; 198
} 199
finally 200
{ 201
SqlQuery = null; 202
} 203
204
} 205
public static int MSSqlExecuteNonQuery(ref string SqlQuery, ref SqlParameter Parameter) 206
{ 207
int result = 0; 208
SqlQuery = SqlQuery.Trim(); 209
if (SqlQuery.Contains("'") || SqlQuery.Contains("--")) 210
return result; 211
try 212
{ 213
using (SqlConnection SqlConn = new SqlConnection(ConnectionString.GetConnStr())) 214
{ 215
SqlCommand SqlCmd = new SqlCommand(SqlQuery, SqlConn); 216
SqlCmd.Parameters.Add(Parameter); 217
SqlConn.Open(); 218
result = SqlCmd.ExecuteNonQuery(); 219
return result; 220
} 221
} 222
catch (SqlException) 223
{ 224
return result; 225
} 226
finally 227
{ 228
SqlQuery = null; 229
} 230
231
} 232
public static int MSSqlExecuteNonQuery(ref string SqlQuery, ref SqlParameter[] Parameters) 233
{ 234
int result = 0; 235
SqlQuery = SqlQuery.Trim(); 236
if (SqlQuery.Contains("'") || SqlQuery.Contains("--")) 237
return result; 238
try 239
{ 240
using (SqlConnection SqlConn = new SqlConnection(ConnectionString.GetConnStr())) 241
{ 242
SqlCommand SqlCmd = new SqlCommand(SqlQuery, SqlConn); 243
SqlCmd.Parameters.AddRange(Parameters); 244
SqlConn.Open(); 245
result = SqlCmd.ExecuteNonQuery(); 246
return result; 247
} 248
} 249
catch (SqlException) 250
{ 251
return result; 252
} 253
finally 254
{ 255
SqlQuery = null; 256
} 257
} 258
} 259
}
附帶一提 ... 靜態類別 在MSND上 的說明
只包含靜態成員。
無法執行個體化 (Instantiated)。
為密封類別。
無法包含執行個體建構函式 (C# 程式設計手冊)。
因此,建立靜態類別就像是建立只包含靜態成員和私用建構函式 (Private Constructor) 的類別。私用建構函式可讓類別避免執行個體化。
使用靜態類別的好處是,編譯器可進行檢查,確定不會在不小心的情況下加入執行個體成員。編譯器將可確保這個類別不會建立執行個體。
靜態類別是密封的,因此無法繼承。靜態類別無法包含建構函式,不過您仍可以宣告靜態建構函式,以指定初始值或設定靜態狀態。如需詳細資訊,請參閱靜態建構函式 (C# 程式設計手冊)。
由於 無法使用繼承 以及不可以宣告執行個體
所以 原本 DataCommand 繼承自 ConnectionString
被我拿掉了 ... 建立執行個體的敘述 也拿掉了
再來 物件模型的部份 (以NEWS 新聞公告版 做為範例) 資料庫架構如下
(歸類在命名空間 DOM 資料物件模型)

using System; 02
namespace DOM 03
{ 04
public class News 05
{ 06
private int _ID; 07
private DateTime _Date; 08
private string _Subject; 09
private string _Content; 10
private bool _Del; 11
private string _Chger; 12
private DateTime _ChgTime; 13
14
public int NewsID 15
{ 16
get { return _ID; } 17
set { _ID = value; } 18
} 19
public DateTime NewsDate 20
{ 21
get { return _Date; } 22
set { _Date = value; } 23
} 24
public string NewsSubject 25
{ 26
get { return _Subject; } 27
set { _Subject = value; } 28
} 29
public string NewsContent 30
{ 31
get { return _Content; } 32
set { _Content = value; } 33
} 34
public bool Del 35
{ 36
get { return _Del; } 37
set { _Del = value; } 38
} 39
public string Chger 40
{ 41
get { return _Chger; } 42
set { _Chger = value; } 43
} 44
public DateTime ChgTime 45
{ 46
get { return _ChgTime; } 47
set { _ChgTime = value; } 48
} 49
50
public News() { } 51
} 52
}單純就是物件的模型 ...對應到資料庫
再來是 增刪改的Query 類別
using System; 02
using System.Collections.Generic; 03
using System.Linq; 04
using System.Text; 05
using System.Data.Common; 06
using System.Data.SqlClient; 07
08
namespace DAL 09
{ 10
public class Query 11
{ 12
protected int IDU(ref string SqlQuery, DOM.dbType Type) 13
{ 14
int result = 0; 15
switch (Type) 16
{ 17
case DOM.dbType.SqlServer: 18
result = SqlServer(ref SqlQuery); 19
break; 20
} 21
return result; 22
} 23
protected int IDU(ref string SqlQuery, ref DbParameter Parameter, DOM.dbType Type) 24
{ 25
int result = 0; 26
switch (Type) 27
{ 28
case DOM.dbType.SqlServer: 29
SqlParameter SP = (SqlParameter)Parameter; 30
result = SqlServer(ref SqlQuery, ref SP); 31
Parameter = null; 32
break; 33
} 34
return result; 35
} 36
protected int IDU(ref string SqlQuery, ref DbParameter[] Parameters, DOM.dbType Type) 37
{ 38
int result = 0; 39
switch (Type) 40
{ 41
case DOM.dbType.SqlServer: 42
SqlParameter[] SP = new SqlParameter[Parameters.Length]; 43
for (int i = 0; i < Parameters.Length; i++) 44
SP[i] = (SqlParameter)Parameters[i]; 45
result = SqlServer(ref SqlQuery, ref SP); 46
Parameters = null; 47
break; 48
49
} 50
return result; 51
} 52
private int SqlServer(ref string SqlQuery) 53
{ 54
return DataCommand.MSSqlExecuteNonQuery(ref SqlQuery); 55
} 56
private int SqlServer(ref string SqlQuery, ref SqlParameter Parameter) 57
{ 58
return DataCommand.MSSqlExecuteNonQuery(ref SqlQuery, ref Parameter); 59
} 60
private int SqlServer(ref string SqlQuery,ref SqlParameter[] Parameters) 61
{ 62
return DataCommand.MSSqlExecuteNonQuery(ref SqlQuery, ref Parameters); 63
} 64
} 65
}
再來 DAL 資料存取層 繼承 增刪改查 ...
using System; 002
using System.Collections.Generic; 003
using System.Data; 004
using System.Data.Common; 005
using System.Data.SqlClient; 006
using System.Linq; 007
using System.Text; 008
009
namespace DAL 010
{ 011
public class News:Query 012
{ 013
public List<DOM.News> GetAll() 014
{ 015
List<DOM.News> rNews = new List<DOM.News>(); 016
rNews.Clear(); 017
string SqlQuery = "SELECT NewsID, NewsDate, NewsSubject, NewsContent, Del, Chger, ChgTime From News"; 018
DataTable dt; 019
if (DataCommand.MSSqlSelectQuery(ref SqlQuery, out dt)) 020
{ 021
foreach (DataRow row in dt.Rows) 022
rNews.Add(new DOM.News() 023
{ 024
NewsID = (int)row[0], 025
NewsDate = (DateTime)row[1], 026
NewsSubject = row[2].ToString(), 027
NewsContent = row[3].ToString(), 028
Del = (bool)row[4], 029
Chger = row[5].ToString(), 030
ChgTime = (DateTime)row[6] 031
}); 032
033
} 034
return rNews; 035
} 036
public List<DOM.News> GetBy(ref int NID) 037
{ 038
List<DOM.News> rNews = new List<DOM.News>(); 039
rNews.Clear(); 040
string SqlQuery = "SELECT NewsID, NewsDate, NewsSubject, NewsContent, Del, Chger, ChgTime From News WHERE (NewsID = @NewsID)"; 041
DataTable dt; 042
SqlParameter Parameter = new SqlParameter("@NewsID", NID); 043
if (DataCommand.MSSqlSelectQuery(ref SqlQuery, ref Parameter, out dt)) 044
{ 045
rNews.Add(new DOM.News() 046
{ 047
NewsID = (int)dt.Rows[0][0], 048
NewsDate = (DateTime)dt.Rows[0][1], 049
NewsSubject = dt.Rows[0][2].ToString(), 050
NewsContent = dt.Rows[0][3].ToString(), 051
Del = (bool)dt.Rows[0][4], 052
Chger = dt.Rows[0][5].ToString(), 053
ChgTime = (DateTime)dt.Rows[0][6] 054
}); 055
} 056
return rNews; 057
} 058
public int Insert(ref DOM.News oNews) 059
{ 060
string SqlQuery = "INSERT INTO [News] ([NewsSubject], [NewsContent], [Chger]) VALUES (@NewsSubject, @NewsContent, @Chger)"; 061
DbParameter[] Parameters = new SqlParameter[] 062
{ 063
new SqlParameter("@NewsSubject", oNews.NewsSubject), 064
new SqlParameter("@NewsContent", oNews.NewsContent), 065
new SqlParameter("@Chger", oNews.Chger) 066
067
}; 068
return base.IDU(ref SqlQuery, ref Parameters, DOM.dbType.SqlServer); 069
} 070
public int SetDelete(ref int NID) 071
{ 072
string SqlQuery = "UPDATE News SET Del = 1 WHERE (NewsID = @Original_NewsID)"; 073
DbParameter Parameter = new SqlParameter("@Original_NewsID", NID); 074
return base.IDU(ref SqlQuery, ref Parameter, DOM.dbType.SqlServer); 075
} 076
public int RevDelete(ref int NID) 077
{ 078
string SqlQuery = "UPDATE News SET Del = 0 WHERE (NewsID = @Original_NewsID)"; 079
DbParameter Parameter = new SqlParameter("@Original_NewsID", NID); 080
return base.IDU(ref SqlQuery, ref Parameter, DOM.dbType.SqlServer); 081
} 082
public int Delete() 083
{ 084
string SqlQuery = "DELETE FROM News WHERE (Del = 1)"; 085
return base.IDU(ref SqlQuery, DOM.dbType.SqlServer); 086
} 087
public int Update(ref DOM.News oNews) 088
{ 089
string SqlQuery = "UPDATE News SET NewsSubject = @NewsSubject, NewsContent = @NewsContent, Del = @Del, Chger = @Chger, ChgTime = @ChgTime WHERE (NewsID = @Original_NewsID)"; 090
DbParameter[] Parameters = new SqlParameter[] 091
{ 092
new SqlParameter("@NewsSubject", oNews.NewsSubject), 093
new SqlParameter("@NewsContent", oNews.NewsContent), 094
new SqlParameter("@Del", oNews.Del), 095
new SqlParameter("@Chger", oNews.Chger), 096
new SqlParameter("@ChgTime", oNews.ChgTime), 097
new SqlParameter("@Original_NewsID", oNews.NewsID) 098
}; 099
return base.IDU(ref SqlQuery, ref Parameters, DOM.dbType.SqlServer); 100
} 101
public News() { } 102
} 103
}
看到了嗎 ...22行的地方 C# 3.0的 Object Initializers 超級好用~
70 76行 下面再做解釋
再來 BLL層
using System; 02
using System.Collections.Generic; 03
04
namespace BLL 05
{ 06
public class News 07
{ 08
private DAL.News dNews; 09
public List<DOM.News> GetAll() 10
{ 11
return dNews.GetAll(); 12
} 13
public List<DOM.News> GetBy(int NID) 14
{ 15
return dNews.GetBy(ref NID); 16
} 17
public int Insert(DOM.News oNews) 18
{ 19
if (oNews.Chger == null) 20
return 0; 21
else 22
return dNews.Insert(ref oNews); 23
} 24
public int Delete(DOM.News oNews) 25
{ 26
int ID = oNews.NewsID; 27
if (oNews.Del) 28
return dNews.SetDelete(ref ID); 29
else 30
return dNews.RevDelete(ref ID); 31
} 32
public int Delete() 33
{ 34
return dNews.Delete(); 35
} 36
public int Update(ref DOM.News oNews) 37
{ 38
if (oNews.Chger == null) 39
return 0; 40
else 41
{ 42
oNews.ChgTime = DateTime.Now; 43
return dNews.Update(ref oNews); 44
} 45
} 46
public News() 47
{ 48
dNews = new DAL.News(); 49
} 50
} 51
}基本上 是和 DAL進行溝通 ...還有處理一些資訊
例如 19行的地方 如果 傳進來的 Chger ( 修改者 )為空 ...
就不做任何事情 直接傳回 0
再來 有關於刪除的部份 做了一些小變動 ...
再資料庫裡面 加入一個 叫做 Del的值 型態為 bit
如果 Del = 1 就代表 待刪除的資料
我在這邊的用意是 在UI的部份 讓使用者 選擇刪除 但是不會真的刪除
只會把 Del 設定成1 (避免誤刪)
只有在呼叫到 Delete(); 才會執行 真正的刪除動作 (Del = 1的全部刪掉)
好像也可以做到 整批刪除的效果 ...^^
再來是36行的部份 也是檢查 Chger 是不是空的 (空的當然不允許)
如果不是,就把ChgTime(修改時間) 加入要寫進資料庫的物件 再傳回給DAL層 做SQL命令
其實也在想 要不要把DAL 寫成靜態類別呢 ...(有機會再試試看)
以上 ...
Phoenix 8/11
using