2011年12月3日 星期六

簡述 Oracle + Enterprise Library 5.0 Data Access Application Block 的操作


接觸並且使用 Enterprise Library (以下簡稱為 EntLib )在專案中開發已經有很長一段時間了,在 Linq to SQL, ADO.NET Entity Framework 出現之前的對資料庫存取都會使用 EntLib 的 Data Access Application Block (DAAB),而不是使用既有的 ADO.NET 操作,使用 DAAB 除了可以讓程式碼撰寫的行數減少一些之外,DAAB 對於 ADO.NET的操作也做了優化,所以使用 DAAB 做資料存取的動作是會比使用原生 ADO.NET 操作方式來得方便,但是不要認為說使用DAAB就可以不用管ADO.NET囉!因為DAAB的內容都還是繞著ADO.NET操作上打轉,DAAB把我們在使用ADO.NET操作的方法都做了包裝。

原本打算要寫一系列有關 Enterprise Library 的文章,但是一直沒有時間好好的規劃撰寫的方向與架構,而且這兩三年來在專案開發上也都是使用 Linq To SQL 或是 ADO.NET Entity Framework 來做為資料存取的 solution,以致於很少有機會再去接觸以及使用 EntLib ……

而最近一個專案的關係,讓我又重拾 EntLib 的使用,因為這個專案使用的是 Oracle 資料庫,原本打算使用 ODAC for Entity Framework,但是……客戶的技術思維還停留在 .NET 2.0 的時代,不要說什麼是 ORM,連什麼叫做LINQ都不知道了,客戶為了日後他們自己維護的方便,所以堅持使用傳統的ADO.NET方式來做為資料存取的解決方案,也就是因為這樣讓我決定使用 EntLib 的 DAAB 來操作對 Oracle 資料庫的存取。


使用傳統的ADO.NET操作資料的讀取

我在 Oracle 資料庫中有個 Table「ARTICLE」,而此 Table 的欄位與資料如下:

image

而我已經習慣用物件的強型別方式來做為資料集合,而不習慣使用 DataSet 或是 DataTable 這些弱型別的資料集合,所以我取出資料後就會去做資料對映的動作,讓從資料庫取出的資料去Mapping我們的物件,以下是我程式中的 Article 類別:

image

public class Article
{
    public string ID
    {
        get;
        set;
    }
 
    public string SUBJECT
    {
        get;
        set;
    }
 
    public string CONTENT
    {
        get;
        set;
    }
 
    public bool IS_PUBLISH
    {
        get;
        set;
    }
 
    public DateTime PUBLISH_DATE
    {
        get;
        set;
    }
 
    public string CREATE_USER
    {
        get;
        set;
    }
 
    public DateTime CREATE_DATE
    {
        get;
        set;
    }
 
    public string UPDATE_USER
    {
        get;
        set;
    }
 
    public DateTime? UPDATE_DATE
    {
        get;
        set;
    }
 
    public Article()
    {
        this.IS_PUBLISH = false;
        this.CREATE_DATE = DateTime.Now;
    }
}

而使用 ADO.NET 取出資料的方式如下:

/// <summary>
/// Finds all.
/// </summary>
/// <returns></returns>
public List<Article> FindAll()
{
  string sql = " select * from ARTICLE order by CREATE_DATE asc ";
 
  using (OracleConnection connection = new OracleConnection(this.connection_string))
  using (OracleCommand command = new OracleCommand(sql, connection))
  {
    try
    {
      if (connection.State != ConnectionState.Open)
      {
        connection.Open();
      }  
 
      List<Article> data = new List<Article>();
 
      using (OracleDataReader reader = command.ExecuteReader(CommandBehavior.CloseConnection))
      {
        while (reader.Read())
        {
          Article item = new Article();
 
          item.ID = DBNull.Value.Equals(reader["ID"]) 
            ? string.Empty 
            : reader["ID"].ToString();
            
          item.SUBJECT = DBNull.Value.Equals(reader["SUBJECT"]) 
            ? string.Empty 
            : reader["SUBJECT"].ToString();
            
          item.CONTENT = DBNull.Value.Equals(reader["CONTENT"]) 
            ? string.Empty 
            : reader["CONTENT"].ToString();
            
          item.IS_PUBLISH = DBNull.Value.Equals(reader["IS_PUBLISH"]) 
            ? false 
            : reader["IS_PUBLISH"].ToString().Equals("1");
          
          item.PUBLISH_DATE = DBNull.Value.Equals(reader["PUBLISH_DATE"]) 
            ? DateTime.MaxValue 
            : Convert.ToDateTime(reader["PUBLISH_DATE"]);
          
          item.CREATE_USER = DBNull.Value.Equals(reader["CREATE_USER"]) 
            ? string.Empty 
            : reader["CREATE_USER"].ToString();
          
          item.CREATE_DATE = DBNull.Value.Equals(reader["CREATE_DATE"]) 
            ? DateTime.Now 
            : Convert.ToDateTime(reader["CREATE_DATE"]);
          
          item.UPDATE_USER = DBNull.Value.Equals(reader["UPDATE_USER"]) 
            ? string.Empty 
            : reader["UPDATE_USER"].ToString();
 
          if (DBNull.Value.Equals(reader["UPDATE_DATE"]))
          {
            item.UPDATE_DATE = null;
          }
          else
          {
            item.UPDATE_DATE = Convert.ToDateTime(reader["UPDATE_DATE"]);  
          }
          data.Add(item);
        }
      }
      return data;
    }
    catch (Exception ex)
    {
      throw;
    }
  }
}

從開啟資料庫連線、建立 Command、使用 DataReader 取得資料集後再去將資料對映到物件,最後返回 Article 的資料集合,而程式中使用這個 Method 的用法如下(我這邊是用 ASP.NET MVC 2.0 來做為前端的顯示):

public ActionResult Index()
{
  DataAccess1 dataAccess1 = new DataAccess1();
  
  var data = dataAccess1.FindAll();
  ViewData["Count"] = data.Count;
  ViewData.Model = data;
 
  return View();
}

顯示結果,畫面中只有顯示幾個欄位:

image

 

可以看到上面那一串取出資料的物件對映是蠻瑣碎的,而且如果取出資料的 Method 一多的話,每個 Method 都要去寫那一段的話就違反了程式的一個基本原則:「不要重複」,所以可以把資料對映到物件的方式給取出,另外建立一個方法,傳入的參數為 IDataReader 型別,

/// <summary>
/// Reads the object.
/// </summary>
/// <param name="reader">The reader.</param>
/// <returns></returns>
private Article ReadObject(IDataReader reader)
{
  Article item = new Article();
 
  item.ID = DBNull.Value.Equals(reader["ID"]) 
    ? string.Empty 
    : reader["ID"].ToString();
 
  item.SUBJECT = DBNull.Value.Equals(reader["SUBJECT"]) 
    ? string.Empty : reader["SUBJECT"].ToString();
 
  item.CONTENT = DBNull.Value.Equals(reader["CONTENT"]) 
    ? string.Empty 
    : reader["CONTENT"].ToString();
 
  item.IS_PUBLISH = DBNull.Value.Equals(reader["IS_PUBLISH"]) 
    ? false 
    : reader["IS_PUBLISH"].ToString().Equals("1");
 
  item.PUBLISH_DATE = DBNull.Value.Equals(reader["PUBLISH_DATE"]) 
    ? DateTime.MaxValue 
    : Convert.ToDateTime(reader["PUBLISH_DATE"]);
 
  item.CREATE_USER = DBNull.Value.Equals(reader["CREATE_USER"]) 
    ? string.Empty 
    : reader["CREATE_USER"].ToString();
 
  item.CREATE_DATE = DBNull.Value.Equals(reader["CREATE_DATE"]) 
    ? DateTime.Now 
    : Convert.ToDateTime(reader["CREATE_DATE"]);
 
  item.UPDATE_USER = DBNull.Value.Equals(reader["UPDATE_USER"]) 
    ? string.Empty 
    : reader["UPDATE_USER"].ToString();
 
  if (DBNull.Value.Equals(reader["UPDATE_DATE"]))
  {
    item.UPDATE_DATE = null;
  }
  else
  {
    item.UPDATE_DATE = Convert.ToDateTime(reader["UPDATE_DATE"]);
  }
  return item;
}
 

 

建立一個 FindOne 方法,用來取出一筆 Article 資料,而這個方法會使用到剛剛建立的 ReadObject(),

/// <summary>
/// Finds the one.
/// </summary>
/// <param name="id">The id.</param>
/// <returns></returns>
public Article FindOne(string id)
{
  string sql = " select * from ARTICLE Where ID = :ID ";
 
  using (OracleConnection connection = new OracleConnection(this.connection_string))
  using (OracleCommand command = new OracleCommand(sql, connection))
  {
    try
    {
      if (connection.State != ConnectionState.Open)
      {
        connection.Open();
      }
 
      command.Parameters.Add("ID", id);
 
      using (OracleDataReader reader = command.ExecuteReader(CommandBehavior.CloseConnection))
      {
        if (reader.Read())
        {
          return this.ReadObject(reader);
        }
      }
      return null;
    }
    catch (Exception ex)
    {
      throw;
    }
  }
}
 

程式中下 SQL 指令的時候,最忌諱的就是所謂的「SQL Injection」,所以不要用「組字串」的方式去產生 SQL 指令,當有資料需要帶入 SQL 指令的時候,這個時候要用參數的方式,然後搭配使用 DbParameter,MS SQL 的 SQL指令中的參數是使用「@」,而 Oracle 的 SQL 指令中的參數則是要使用「:」(冒號),而 OracleParameter 中的 ParameterName 則只要填入參數名稱就好,不需要加入「:」(冒號),這個方法中,就使用了 ReadObject() 方法來取代原本的對映方式,因為 FindOne() 方法只是取出一筆資料而已,所以另外建立一個 FindByCreateUser() 方法,返回 Artcle 的集合資料,

/// <summary>
/// Finds the by create user.
/// </summary>
/// <param name="user">The user.</param>
/// <returns></returns>
public List<Article> FindByCreateUser(string user)
{
  string sql = @" select * from ARTICLE where CREATE_USER = :CREATE_USER order by CREATE_DATE asc ";
 
  using (OracleConnection connection = new OracleConnection(this.connection_string))
  using (OracleCommand command = new OracleCommand(sql, connection))
  {
    try
    {
      if (connection.State != ConnectionState.Open)
      {
        connection.Open();
      }
 
      command.Parameters.Add("CREATE_USER", user);
 
      using (OracleDataReader reader = command.ExecuteReader(CommandBehavior.CloseConnection))
      {
        List<Article> articles = new List<Article>();
 
        while (reader.Read())
        {
          articles.Add(this.ReadObject(reader));
        }
        return articles;
      }
    }
    catch (Exception ex)
    {
      throw;
    }
  }
}

使用 FindByCreateUser() 方法的執行結果:

image

 

一定有人會說,希望查詢的欄位可以動態的去增減,最後是可以自定欄位,而不希望去增加一堆 Find 的方法,所以我就簡單做了一個可以讓USER去動態自訂欄位的方法,先說明這只是一個簡單的實作,並不適用於複雜的查詢操作上。

實作程式如下:

FindByCondition() 方法,傳入的參數為 Dictionary<string, object>,Dictionary 的 Key 為表格的欄位名稱,Dictionaryt 的 Value 就是查詢值,

/// <summary>
/// Finds the by conditions.
/// </summary>
/// <param name="columnValue">The column value.</param>
/// <returns></returns>
public List<Article> FindByConditions(Dictionary<string, object> columnValue)
{
  //Prepare Where Clause and OracleParameter
 
  List<string> whereClause = new List<string>();
  List<OracleParameter> parameters = new List<OracleParameter>();
 
  foreach (var item in columnValue)
  {
    if (!item.Key.Equals(string.Empty) && !item.Value.Equals(null))
    {
      whereClause.Add(string.Format(@"{0} = :{0}", item.Key));
      parameters.Add(new OracleParameter(item.Key, item.Value));
    }
  }
       
  string sql = string.Format(@" select * from Article where {0} order by CREATE_DATE desc ", string.Join(" and  ", whereClause.ToArray()));
 
  using (OracleConnection connection = new OracleConnection(this.connection_string))
  using (OracleCommand command = new OracleCommand(sql, connection))
  {
    try
    {
      if (connection.State != ConnectionState.Open)
      {
        connection.Open();
      }
 
      command.Parameters.AddRange(parameters.ToArray());
 
      using (OracleDataReader reader = command.ExecuteReader(CommandBehavior.CloseConnection))
      {
        List<Article> articles = new List<Article>();
 
        while (reader.Read())
        {
          articles.Add(this.ReadObject(reader));
        }
        return articles;
      }
    }
    catch (Exception ex)
    {
      throw;
    }
  }  
 
}
 

使用這個方法:

public ActionResult About()
{
  DataAccess1 dataAccess = new DataAccess1();
 
  Dictionary<string, object> conditions = new Dictionary<string, object>();
  conditions.Add("IS_PUBLISH", 1);
  conditions.Add("CREATE_USER", "AAA");
 
  var data = dataAccess.FindByConditions(conditions);
 
  ViewData["Count"] = data.Count;
  ViewData.Model = data;
 
  return View();
}
 

執行結果:

image

 

以上就是使用傳統的ADO.NET方法去讀取Oracle資料庫的方式,其實也不是說這樣的方式不好,但是很多的動作都要重複做就覺得瑣碎,接下來就介紹怎麼將前面那些資料操作使用 Enterprise Library Data Access Application Block 來操作。

 


 

Microsoft Enterprise Library 5.0

http://msdn.microsoft.com/en-us/library/ff632023.aspx

http://entlib.codeplex.com/

Enterprise Library 5.0 Class Library on MSDN

學習範例

Microsoft Enterprise Library 5.0 Hands-on Labs

Microsoft Enterprise Library 5.0 Extensibility Hands-on Labs

The Data Access Application Block

http://msdn.microsoft.com/en-us/library/ff664408(v=PandP.50).aspx

 

使用 Nuget 加入 Enterprise Library 的 Data Access Application Block 參考

在專案中去開啟「Manage NuGet Packages…」

image

開啟「Manage NuGet Paclages」視窗後,先在右上方的的搜尋列中輸入「Enterprise Library」後就會在中間列出相關的packages,而我們要選擇加入的是「Enterprise Library 5.0 – Data Access Application Block」

SNAGHTML38e982c

安裝後在「Installed packages」可以看到安裝 EntLib 5.0 DAAB 後所加入的參考

SNAGHTML3916d07

除了使用NuGet安裝EntLib 5.0 DAAB外,也可以直接到EntLib的網站中去下載安裝檔或是組件檔,然後在專案中使用加入參考的方式去把相關的組件給加入。

 

使用Enterprise Library的Data Access Application Block方式來讀取Oracle資料庫中的資料

加入相關的參考後就開始使用EntLib DAAB來建立剛才使用傳統ADO.NET讀取方式的Methods,在程式中要加入使用的 Namespace 有兩個:

using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Data;

首先要在程式中先建立 DAAB 的 instance:

private Database _db;
protected Database db
{
    get
    {
        if (_db == null)
        {
            _db = EnterpriseLibraryContainer.Current.GetInstance<Database>("OracleNorthwind");
        }
        return _db;
    }
}

FindAll() 方法:

/// <summary>
/// Finds all.
/// </summary>
/// <returns></returns>
public List<Article> FindAll()
{
  string sql = " select * from ARTICLE order by CREATE_DATE asc ";
 
  using (DbCommand command = db.GetSqlStringCommand(sql))
  {
    try
    {
      List<Article> data = new List<Article>();
 
      using (IDataReader reader = db.ExecuteReader(command))
      {
        while (reader.Read())
        {
          data.Add(this.ReadObject(reader));
        }
      }
      return data;
    }
    catch (Exception ex)
    {
      throw;
    }
  }
}

可以與使用傳統 ADO.NET 方式的 FindAll() 做個比較,使用 EntLib DAAB 不需另外建立 DbConnection,也不需要在 DbCommand 中指定 DbConnection,也不需要去開啟 DbConnection,使用 DAAB 的 GetSqlStringCommand() 方法,這個方法就會幫我們做到這些動作。

FindAll() 方法使用:

public ActionResult Index()
{
  DataAccess2 dataAccess = new DataAccess2();
 
  var data = dataAccess.FindByCreateUser("AAA");
  ViewData["Count"] = data.Count;
  ViewData.Model = data;
 
  return View();
}

程式執行結果:

image

 

建立一個使用 EntLib DAAB 的 FindByCreateUser() 方法,

/// <summary>
/// Finds the by create user.
/// </summary>
/// <param name="user">The user.</param>
/// <returns></returns>
public List<Article> FindByCreateUser(string user)
{
  string sql = @" select * from ARTICLE where CREATE_USER = :CREATE_USER order by CREATE_DATE asc ";
 
  using (DbCommand command = db.GetSqlStringCommand(sql))
  {
    command.Parameters.Add(new OracleParameter("CREATE_USER", user));
 
    try
    {
      using (IDataReader reader = db.ExecuteReader(command))
      {
        List<Article> articles = new List<Article>();
 
        while (reader.Read())
        {
          articles.Add(this.ReadObject(reader));
        }
        return articles;
      }
    }
    catch (Exception ex)
    {
      throw;
    }
  }
}

如同上一個方法的比較,使用EntLib DAAB的FindByCreateUser()的程式碼是比原本使用傳統ADO.NET方式要減少許多,至於FindBuConditions()方法,這邊就不實作出來,可讓各位去自行嘗試。

 

使用 DAAB 的 Data Accessor

看到這裡,或許有些人覺得使用DAAB或許是有比傳統ADO.NET的資料讀取方式要方便,但改變的幅度並不是很多,其實DAAB還有提供另一個資料讀取的方式,Data Accessor.

在上面無論是不是用傳統 ADO.NET 方式或是使用 DAAB 來讀取資料,在程式中為了要對映到我們所自訂的 Article物件,程式之中都用的 ReadObject() 方法,這是為了要讓資料Mapping到物件的操作,而DAAB也有提供同樣的方法:「Data Accessor」,而這必須搭配兩個介面來使用「IRowMapper」「IParameterMapper」。

相關的詳細資料與操作可以參考MSDN的說明:

Returning Data as Objects for Client Side Querying:http://msdn.microsoft.com/en-us/library/ff664431(v=PandP.50).aspx

 

以下是使用 Data Accessor 的程式,同樣也是實作之前的 FindAll() 與 FindByCreateUser() 方法。

首先是要先建立實作IRowMapper的類別:

IRowMapper的實作就只有一個方法,MapRow,傳入的參數型別為IDataRecord,

public class SomeObjectMapper : IRowMapper<Article>
{
    public Article MapRow(IDataRecord row)
    {
        throw new NotImplementedException();
    }
}

 

我們之前所做的ReadObject()方法所傳入的是IDataReader,而剛好IDataReader也是實作IDataRecord,

所以我們就可以沿用ReadObject()方法的程式。

IDataReader Interface:http://msdn.microsoft.com/en-us/library/system.data.idatareader.aspx

IDataRecord Interface:http://msdn.microsoft.com/en-us/library/system.data.idatarecord.aspx

 

ArticleMapper類別

//=========================================================================================
//IRowMapper
 
public class ArticleMapper : IRowMapper<Article>
{
  public Article MapRow(IDataRecord reader)
  {
    Article item = new Article();
 
 
    item.ID = DBNull.Value.Equals(reader["ID"]) 
        ? string.Empty 
        : reader["ID"].ToString();
 
    item.SUBJECT = DBNull.Value.Equals(reader["SUBJECT"]) 
        ? string.Empty 
        : reader["SUBJECT"].ToString();
 
    item.CONTENT = DBNull.Value.Equals(reader["CONTENT"]) 
        ? string.Empty 
        : reader["CONTENT"].ToString();
 
    item.IS_PUBLISH = DBNull.Value.Equals(reader["IS_PUBLISH"]) 
        ? false 
        : reader["IS_PUBLISH"].ToString().Equals("1");
 
    item.PUBLISH_DATE = DBNull.Value.Equals(reader["PUBLISH_DATE"]) 
        ? DateTime.MaxValue 
        : Convert.ToDateTime(reader["PUBLISH_DATE"]);
 
    item.CREATE_USER = DBNull.Value.Equals(reader["CREATE_USER"]) 
        ? string.Empty 
        : reader["CREATE_USER"].ToString();
 
    item.CREATE_DATE = DBNull.Value.Equals(reader["CREATE_DATE"]) 
        ? DateTime.Now 
        : Convert.ToDateTime(reader["CREATE_DATE"]);
 
    item.UPDATE_USER = DBNull.Value.Equals(reader["UPDATE_USER"]) 
        ? string.Empty 
        : reader["UPDATE_USER"].ToString();
 
    if (DBNull.Value.Equals(reader["UPDATE_DATE"]))
    {
      item.UPDATE_DATE = null;
    }
    else
    {
      item.UPDATE_DATE = Convert.ToDateTime(reader["UPDATE_DATE"]);
    }
 
    return item;
  }
}

接下來看看使用DataAccssor的FindAll()方法實作:

/// <summary>
/// Finds all.
/// </summary>
/// <returns></returns>
public List<Article> FindAll()
{
  string sql = " select * from ARTICLE order by CREATE_DATE asc ";
 
  try
  {
    DataAccessor<Article> accessor = db.CreateSqlStringAccessor<Article>(sql, new ArticleMapper());
    var data = accessor.Execute().ToList();
    return data;
  }
  catch (Exception ex)
  {
    throw;
  }
}

程式整個精簡了不少,而且透過DataAccessor的操作就讓從資料庫所取得的資料自動對映到物件集合中。

 

而接下來我們要來使用 DataAccssor 來實作 FindByCreateUser() 方法,使用 DataAccssor 又要使用到 Parameter時,這時候就無法在 DbCommand 加入 Parameter 的方式,就必須要事先建立一個實作 IParameterMapper 介面的類別,然後實作其唯一的方法 AssignParameters():

public class SomeDataParameterMapper : IParameterMapper
{
    public void AssignParameters(DbCommand command, object[] parameterValues)
    {
        throw new NotImplementedException();
    }
}

我們在 FindByCreateUser() 方法中所使用的 SQL 指令是:

string sql = @" select * from ARTICLE where CREATE_USER = :CREATE_USER order by CREATE_DATE asc ";

所以我們所建立的 FindByCreateUserParameterMapper 類別如下:

public class FindByCreateUserParameterMapper : IParameterMapper
{
    public void AssignParameters(DbCommand command, object[] parameterValues)
    {
        command.Parameters.Add(new OracleParameter("CREATE_USER", parameterValues[0]));
    }
}

這邊要注意的是 Parameter 的加入順序,在稍後使用的時候一定要依照 Parameter 加入的順序去填入 Parameter Value。

 

我們建立了 ArticleMapper 以及 FindByCreateUserParameterMapper 這兩個類別,接下來就是方法的實作與使用,

FindByCreateUser()方法:

/// <summary>
/// Finds the by create user.
/// </summary>
/// <param name="user">The user.</param>
/// <returns></returns>
public List<Article> FindByCreateUser(string user)
{
    string sql = @" select * from ARTICLE where CREATE_USER = :CREATE_USER order by CREATE_DATE asc ";
 
    try
    {
        DataAccessor<Article> accessor = db.CreateSqlStringAccessor<Article>(sql, new FindByCreateUserParameterMapper(), new ArticleMapper());
        var data = accessor.Execute(new object[] { user }).ToList();
        return data;
    }
    catch (Exception ex)
    {
        throw;
    }
}
 

CreateSqlStringAccessor() 方法還有以下的一個多載:

CreateSqlStringAccessor(TResult) Method (Database, String, IParameterMapper, IRowMapper(TResult))

這個方法傳入參數除了 SQL Statement 外,另外還有 IParameterMapper 與 IRowMapper,這也就是我們剛才所建立的 FindByCreateUserParameterMapper 與 ArticleMapper 這兩個類別,剛才有說到,在FindByCreateUserParameterMapper 類別的 AssignParameters() 方法,要注意加入 Parameter 的順序,在DataAccessor.Execute() 的方法中就需要傳入 Parameter 的值,而這個 Parameter Value 的加入順序就一定要依照AssignParameters()方法裡DbCommand加入Parameter的順序。

以上我們從傳統的 ADO.NET 讀取資料庫的方式,進而改使用 EntLib DAAB 的方法來讀取資料庫,最後就是改使用DataAccessor 的方式,可以看到方法個改變而讓程式的撰寫更為精進與精簡,但是這邊只是做個簡單的程式示範與介紹,在實務上的應用還是必須再做一些的修改與重構。

例如最後使用 DataAccessor 的方式,在我接接觸並且使用的過程中總是會產生一個疑問,實作 IRowMapper 的類別建立一個就可以,但是建立實作 IParameterMapper 的類別會因為方法與查詢的 SQL Statement 不同而要增加多個,如果遇到需要動態增減 Parameter 時,那麼實作 IParameterMapper 的類別應該要如何建立呢?

(其實比較好的方式就是看需求來決定要使用哪一種,要動態增減參數的時候,還是使用DAAB原本的方法)

因為是 Oracle 資料庫並且又無法使用ORM的情況下,我又一定要用物件導向的操作,所以我就做了這樣的應用,對於無法使用 ORM 技術(Linq to SQL, ADO.NET Entity Frameworl or ODAC for Entity Framework…etc)而必須使用 ADO.NET 技術來做為資料存取 Solution 的專案開發提供另一個解決方案。

後續如果有時間的話,再對 Enterprise Library 做一個比較完整的介紹,畢竟 EntLib 是個相當不錯的 Library,不是要我們改變原本程式中使用 .NET Framework 的架構,而是使用EntLib來加強原本程式的架構,如同它的名稱是「Library」而非「Framework」

 

以上

5 則留言:

  1. 請教版主,
    使用 EntLib 時,當遇到sqlStatement 中有 where in ('A','B',...) 之類的語法時,在設計 ParameterMapper 總是不順,
    對於這類有否其他更好的撰寫方式?

    回覆刪除
    回覆
    1. 這個我這邊沒有什麼比較好的建議,我還是使用一個一個的對映做處理,不然就是跑個迴圈,然後組成 in clause 裡所使用的字串然後帶入 parameter 裡,可以參靠下面文章的作法(部知道這是不是符合你的情形,不用看最下面 LINQ 方式,看 ADO.NET 的方式)
      Parameterized IN clauses with ADO.NET and LINQ
      http://www.mikesdotnetting.com/Article/116/Parameterized-IN-clauses-with-ADO.NET-and-LINQ

      刪除
  2. 請問,有時候會碰到連線字串是需要加密的情況,這部分 EntLib 要怎麼處理?

    回覆刪除
    回覆
    1. Hello, 你好
      如果是使用 EntLib5 以前的版本,可以使用 configuration tools 然後搭配 Cryptography Application Blocks 來完成,可參考以下連結(http://msdn.microsoft.com/en-us/library/ff664594(v=pandp.50).aspx),或是查詢「Enterprise Library Cryptography Application Blocks」
      http://www.cnblogs.com/huangcong/archive/2010/05/28/1746634.html
      http://www.cnblogs.com/huangcong/archive/2010/05/29/1747015.html

      如果是使用 EntLib 6 的話,因為已將 Cryptography Application Blocks 移出去了,不過官方文件還是有提供如何對設定檔加密處理的文章,可以看下的連結:
      MSDN - Enterprise Library 6 - Appendix B - Encrypting Configuration Files
      http://msdn.microsoft.com/en-us/library/dn440730(v=pandp.60).aspx

      刪除

提醒

千萬不要使用 Google Talk (Hangouts) 或 Facebook 及時通訊與我聯繫、提問,因為會掉訊息甚至我是過了好幾天之後才發現到你曾經傳給我訊息過,請多多使用「詢問與建議」(在左邊,就在左邊),另外比較深入的問題討論,或是有牽涉到你實作程式碼的內容,不適合在留言板裡留言討論,請務必使用「詢問與建議」功能(可以夾帶檔案),謝謝。