先看看PetShop內DALFactory內資料處理站與資料庫互動的根源-SQLServerDAL,採用的是SqlHelper.cs這一類檔案,相信大家對這個都不會感到陌生了.在做PetShop的資料庫訪問之前,首先對關係進行對象建模,即我們通常所說到的O/R模型,在Modle層中對[Account]表中關於使用者地址[Address]進行建模,[當然,這是微軟開發小組對於對象粒度的劃分,你也可以擴充到抽取Account部分的Balance等等進行擴充],這種思路對於今後的資料庫擴充發生的連帶影響可以降低到最少.And I like it^^
namespace PetShop.Model {
/// <summary>
/// Business entity used to model addresses
/// </summary>
[Serializable]
public class AddressInfo {
// Internal member variables
private string _firstName;
private string _lastName;
private string _address1;
private string _address2;
private string _city;
private string _state;
private string _zip;
private string _country;
private string _phone;
public AddressInfo(string firstName, string lastName, string address1, string address2, string city, string state, string zip, string country, string phone) {
this._firstName = firstName;
this._lastName = lastName;
this._address1 = address1;
this._address2 = address2;
this._city = city;
this._state = state;
this._zip = zip;
this._country = country;
this._phone = phone;
}
}
}
以上,我省略了所有屬性,只把主幹模型抽取出來討論
在底層的IDAL Interface Data Access Logic Layer我們可以看到用到的SQLCommand.Text以及採用的是DataReader以類似指標的方法返回結果,只滿足所需的最小資料量,而不是用整個DataSet作為資料轉送媒介,
將原先所做的模型進列欄位對應,從而在以後如果資料庫擴充欄位,只需要調整Model以及訪問函數一次即可,其它BizLogic則正常運轉.看看代碼:
namespace PetShop.SQLServerDAL {
/// <summary>
/// Summary description for AccountDALC.
/// </summary>
public class Account : IAccount{
private const string SQL_SELECT_ACCOUNT = "SELECT Account.Email, Account.FirstName, Account.LastName, Account.Addr1, Account.Addr2, Account.City, Account.State, Account.Zip, Account.Country, Account.Phone, Profile.LangPref, Profile.FavCategory, Profile.MyListOpt, Profile.BannerOpt FROM Account INNER JOIN Profile ON Account.UserId = Profile.UserId INNER JOIN SignOn ON Account.UserId = SignOn.UserName WHERE SignOn.UserName = @UserId AND SignOn.Password = @Password";
/// <summary>
/// 對返回結果集Mapping到Address模型 /// </summary>
/// <param name="userId"></param>
/// <returns></returns>
public AddressInfo GetAddress(string userId) {
AddressInfo address= null;
SqlParameter[] addressParms = GetAddressParameters();
addressParms[0].Value = userId;
using (SqlDataReader rdr = SQLHelper.ExecuteReader(SQLHelper.CONN_STRING_NON_DTC, CommandType.Text, SQL_SELECT_ADDRESS, addressParms)) {
if (rdr.Read()) {
address = new AddressInfo(rdr.GetString(0), rdr.GetString(1), rdr.GetString(2), rdr.GetString(3), rdr.GetString(4), rdr.GetString(5), rdr.GetString(6), rdr.GetString(7), rdr.GetString(8));
}
}
return address;
}
我省略了Connection那些欄位.在Ado.Net中,我們都知道DataSet是取消連結的,是放在系統記憶體中的,PetShop在開啟資料連線之後,並沒有馬上讀取資料,而是將DataReader傳遞給另外的對象來執行資料讀的操作,然後才關閉串連。這樣,資料連線的時間加長了,而資料庫連接是一項非常寶貴的伺服器資源,相比之下,Dawamish在串連資料庫之後馬上進行填充,然後迅速釋放掉資料庫連接的方式更加有利於大量使用者的並發訪問.因此個人認為對於Master這種配置表還是應該一次性讀出,畢竟在一般應用中,客戶Account表一般不超過10000條,作為訪問量高的資料,只需要定時重新整理記憶體,然後資料訪問只需用Rowfilter進行檢索即可,避開對連結的頻繁互動,在實際應用中會有更好的效果.而對於訂單Orders這種還是對資料庫進行RealTime訪問比較合適.畢竟對於企業級開發來說,程式的健壯性,穩定性,效能是首要考慮的.
我們再來看看Duwamish得資料訪問,前期工作是對錶DataTable進行對應,以避免下次重複寫那麼多遍欄位名,煩都煩死了,那可是體力活,我上次維護的110 個欄位採用的那種架構真是恐怖,寫好模組,我都背出來110個欄位了,TMD
public class Customers : IDisposable
{
//
// DataSetCommand object
//
private SqlDataAdapter dsCommand;
//
// Stored procedure parameter names
//
private const String PKID_PARM = "@PKId";
private const String EMAIL_PARM = "@Email";
private const String NAME_PARM = "@Name";
private const String ADDRESS_PARM = "@Address";
private const String COUNTRY_PARM = "@Country";
private const String PASSWORD_PARM = "@Password";
private const String PHONE_PARM = "@PhoneNumber";
private const String FAX_PARM = "@Fax";
/// <summary>
/// Constructor for Customers.
/// <remarks>Initialize the internal DataSetCommand object.</remarks>
/// </summary>
public Customers()
{
//
// Create the DataSetCommand
//
dsCommand = new SqlDataAdapter();
dsCommand.TableMappings.Add("Table", CustomerData.CUSTOMERS_TABLE);
}
} // class Customers
} // namespace Duwamish7.DataAccess
public CustomerData GetCustomerByEmail(String emailAddress, String password)
{
//
// Check preconditions
//
ApplicationAssert.CheckCondition(emailAddress != String.Empty, "Email address is required",
ApplicationAssert.LineNumber);
ApplicationAssert.CheckCondition(password != String.Empty, "Password is required",
ApplicationAssert.LineNumber);
//
// Get the customer dataSet
//
CustomerData dataSet;
using (DataAccess.Customers customersDataAccess = new DataAccess.Customers())
{
dataSet = customersDataAccess.LoadCustomerByEmail(emailAddress);
}
//
// Verify the customer's password
//
DataRowCollection rows = dataSet.Tables[CustomerData.CUSTOMERS_TABLE].Rows;
if ( ( rows.Count == 1 ) && rows[0][CustomerData.PASSWORD_FIELD].Equals(password) )
{
return dataSet;
}
else
{
return null;
}
}
不過現在開發有了很多O/R Mapping工具,很多映射代碼都可以交給他們處理,畢竟企業級開發要做的好,賣點還是在於你的商務邏輯強悍,能確實幫他們分析問題解決問題,並在知識庫中提供參考依據.用DataSet 還有一個好處就是在於返回DataSet或者DataTable,可以用.Net Framework內建的DataSet.ReadXML,DataSet.GetXML進行XML轉換操作,不過據說開銷比較大,對於XML這個跨平台的媒介來說,基本上主要用於訂單,財務報表和配置部分較多,一般應用中不會引起很大開銷.
對了,我還有一個菜鳥級的問題,我怎麼能貼彩色的源碼啊,這個Blogger內建的Style->Code方法發布出來的代碼太難看了,都看不清楚關鍵字,希望有那位大俠告知.Thanks ^^