最近在瀏覽網路文章時發現微軟的 Enterprise Library, 雖然不是什麼新東西(2005年就發表第一版), 目前的版本是 6.0(April 2013),但發現 Enterprise Library 竟然是 open source 的, 看了一些範例程式發現裡頭大量使用一些 Design Pattern 來簡化目前程式,激起了我研究他的興趣, 因為工作的關係現在比較少機會接觸到微軟的程式, 但他裡頭的設計方式是值得學習和研究的, 想要了解這 Library 第一步驟當然要先學會如何使用它, 先從連接資料庫的部分開始
首先 Refrences 加入 Microsoft.Practices.EnterpriseLibrary.Data
using directive
using Microsoft.Practices.EnterpriseLibrary.Data;
在不使用 LINQ 和 Entity Framework 的狀況下,如果要將資料庫裡的資料轉變成為強型別的物件
1. 在未使用 Enterprise Library 之前原本的做法
public List<Customer> FindCustById1(String connName, String id)
{
String sql = @"SELECT * FROM CUSTOMERS WHERE CUSTOMERID = :ID";
String connString = ConfigurationManager.ConnectionStrings[connName].ConnectionString;
using (OracleConnection connection = new OracleConnection(connString))
using (OracleCommand cmd = new OracleCommand(sql, connection))
{
connection.Open();
cmd.Parameters.Add("ID", id);
List<Customer> data = new List<Customer>();
using (OracleDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection))
{
while (reader.Read())
{
Customer item = new Customer();
item.CustomerId = reader["CUSTOMERID"] == DBNull.Value ? "" : reader["CUSTOMERID"].ToString();
item.CompanyName = reader["COMPANYNAME"] == DBNull.Value ? "" : reader["COMPANYNAME"].ToString();
item.Fax = reader["FAX"] == DBNull.Value ? "" : reader["FAX"].ToString();
item.Address = reader["ADDRESS"] == DBNull.Value ? "" : reader["ADDRESS"].ToString()
data.Add(item);
}
}
return data;
}
}
2. 使用 Enterprise Library,主要精簡了取 Connection 和 物件換的部分,將 Coonection 的建立和關閉封裝在 Database 物件內, 並利用反射將 reader 取得的資料放入 Customer 內
public List<Customer> FindCustById2(String connName, String id)
{
String sql = @"SELECT * FROM CUSTOMERS WHERE CUSTOMERID = :ID";
Database db = DatabaseFactory.CreateDatabase(connName);
using (DbCommand cmd = db.GetSqlStringCommand(sql))
{
db.AddInParameter(cmd, "ID", DbType.String, id);
List<Customer> data = new List<Customer>();
using (IDataReader reader = db.ExecuteReader(cmd))
{
while (reader.Read())
{
Customer item = MapBuilder<Customer>.BuildAllProperties().MapRow(reader);
data.Add(item);
}
}
return data;
}
}
3. 使用 Enterprise Library 進階版, 更進一步的將 reader 轉成物件的部分簡化了, 但是要多寫一個 class, C# 目前(2013年)似乎無法用匿名的方式 implements interface
public List<Customer> FindCustById3(String connName, String id)
{
String sql = @"SELECT * FROM CUSTOMERS WHERE CUSTOMERID = :ID";
Database db = DatabaseFactory.CreateDatabase(connName);
DataAccessor<Customer> accessor = db.CreateSqlStringAccessor<Customer>(sql, new MyParameterMapper());
IEnumerable<Customer> result = accessor.Execute(id);
return new List<Customer>(result);
}
class MyParameterMapper : IParameterMapper
{
public void AssignParameters(DbCommand command, object[] parameterValues)
{
DbParameter parameter = command.CreateParameter();
parameter.ParameterName = ":ID";
parameter.Value = parameterValues[0];
command.Parameters.Add(parameter);
}
}
Enterprise Library 的 Database 物件感覺跟 Spring 的 JdbcTemplate 有點類似, 兩者都將 connection 的開關封裝起來, 並可自定 RowMapper 物件, 建立轉換的規則
使用 Enterprise Library 查詢 Table 內全部資料, 在沒有查詢條件的狀況下程式碼更精簡了
public List<Customer> FindAllCust(String connectiopnName)
{
String sql = @"SELECT * FROM CUSTOMERS";
Database db = DatabaseFactory.CreateDatabase(connectiopnName);
IEnumerable<Customer> result = db.ExecuteSqlStringAccessor<Customer>(sql);
return new List<Customer>(result);
}
總結 : 使用 Enterprise Library 優點
1.簡化存取資料庫的程式碼
2.封裝 connction 開關動作,避免忘記關閉的情形
3.將 conneection 物件包裹起來, 避免程式碼和特定資料庫的 connection 實作產生依賴, 在使用標準的 ANSI SQL 情形下, 只要改改 config 就可以達到抽換不同種類資料庫的目標
Customer.cs
using System;
namespace TestEnterpriseLibrary
{
class Customer
{
public String CustomerId
{
get;
set;
}
public String CompanyName
{
get;
set;
}
public String Fax
{
get;
set;
}
public String Address
{
get;
set;
}
}
}
App.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<connStrings>
<add name="testdb" connString="Data Source=test;User Id=testdb;Password=testdb;" providerName="Oracle.DataAccess.Client" />
</connStrings>
</configuration>