2011-02-24 115 views
1

我正在設計一個WCF服務,該服務將由數百個客戶端調用,並且我有一個關於數據庫查詢將運行的類的最佳體系結構的問題。今天我只能訪問SQL Server,所以我有一個靜態類,我在內部調用它來完成創建連接和數據收集器的所有骯髒工作。下面是一個簡單的例子:用於數據庫幫助程序類的C#設計模式

namespace DBHelper.Utility 
{ 
    public static class SqlDBManager 
    { 
    public static void RunSql(String pSql, DBParamsHelper pDBParams, String pConnStringConfigName) 
    { 
     String sConnectionString = GetConnectionStringFromConfig(pConnStringConfigName); 
     SqlConnection oConn = new SqlConnectionsConnectionString 
     oConn.Open(); 
     try 
     { 
     SqlCommand oCommand = new SqlCommand(pSql, oConn); 
     oCommand.CommandTimeout = 0; 
     if (pDBManagerParams != null) 
     { 
      foreach (SqlParameter sqlParam in pDBManagerParams) 
      { 
      oCommand.Parameters.Add(sqlParam); 
      } 
     } 
     oCommand.ExecuteNonQuery(); 
     } 
     finally 
     { 
     oConn.Close(); 
     } 
    } 
    } 
} 

現在,我需要添加對運行Sql Server和Oracle的支持。我最初的想法是聲明一個接口,並讓我現有的SqlDBManager實現它,然後開發一個實現相同接口的OracleDBManager。問題是我的類是靜態的,而靜態類不能實現一個接口。我希望我的助手類保持靜態,它更加實用,並且我不必在每次需要運行查詢時都創建一個新對象。我也想過使用類繼承,但是我不能擁有statis虛擬方法,所以在那裏用處不大。我考慮過一些單例實現,所以我不需要創建類,但是在多線程訪問中我會遇到麻煩。
什麼是最好的設計模式,所以我可以在多線程場景(非常重要)上有很好的性能,不需要爲生產效率編寫太多工作代碼(不必創建很多類),並且對於OracleDBManager都有一個標準方法和SqlDBManager類?標準方法非常重要,因爲我不希望使用這些助手類的代碼知道它們是否連接到Oracle或Sql Server。
我確實考慮過使用ORM解決方案,比如Entity Framework 4和nHibernate,但是性能影響太大。由於我將運行簡單的查詢,因此PL-SQL和TSQL之間的查詢語法差異將無關緊要。
任何輸入和想法將不勝感激。 TKS

回答

2

接口是正確的方向,但正如您已經指出的那樣,您不能讓靜態類實現接口。我明白想要儘量減少對象創建的煩惱,但爲了有兩個不同的數據庫類,這可能是必要的。

我建議的解決方案是多方面的。首先是用類似簽名的接口你上面列出:

public Interface IDbManager { 
    void RunSql(String pSql, DBParamsHelper pDBParams, String pConnStringConfigName) 
} 

,可以在特定的SQL-甲骨文和版本來實現,你已經擁有了SQL版本,只是讓非靜態和落實接口。

現在嘗試數據庫工廠,也許這樣的:

public static class DbFactory { 
    public static IDbManager CreateDb(DbType type) { 
     select (type) { 
      case DbType.Sql: 
       return new SqlDbManager(); 
       break; 
      case DbType.Sql: 
       return new OracleDbManager(); 
       break; 
     } 
    } 
} 

那麼你應該能夠做這樣的事情:

var db = DbFactory.CreateDb(DbType.Sql); 
db.RunQuery(...); 

此代碼是未經測試,但希望你的想法。對於我需要從不同數據存儲獲取數據的其中一個項目,我使用了類似的解決方案。戰略和工廠模式緩解了這一過程。

希望有幫助!

+0

格蘭特,tks給你的建議。這正是我想到的,有一個工廠班和調查員。只是想避免創建對象,但真的不知道是否有辦法...... Tks! – Pascal 2011-02-24 23:43:47

+0

我認爲避免創建對象的唯一方法是堅持單個靜態類,並在每次需要創建數據庫對象時使用數據庫類型的開關。我最初在上述項目中做了這個 - 太麻煩了!然後,我將數據訪問權改爲我剛纔介紹的內容;它非常簡單,而且便於不同數據提供者的專業課程。 – 2011-02-24 23:54:32

2

爲什麼不把你的靜態方法私人,包裹在一個接口的類支持MS-SQL/Oracle和調用各個界面上的私人靜態方法?

E.g:

public interface ISqlDbManager 
{ 
    void SaveOrder(Order o); 
    void FindOrderById(int orderId); 
} 

public class SqlServerDbManager : ISqlDbManager 
{ 
    private static void RunSql(String pSql, DBParamsHelper pDBParams, String pConnStringConfigName) 
    { 
     // implement as you did above 
    } 

    public void FindOrderById(int orderId) 
    { 
     // create SQL, call private "RunSql" method. 
    } 
} 

做其他的實現(OracleDbManager)同樣的事情。

它是私有的,因爲消費者不應該關心底層持久性機制如何工作。

這也將使單元測試更容易 - 創建一個「MockDbManager」類,其中私有靜態方法在內存列表中執行基本的LINQ操作。

關於旁註,我會強烈推薦使用存儲過程,而不是手動構建sql命令。更適合查詢計劃緩存/優化。

+0

我完全同意procs建議。但是,我需要爲每個業務對象重複數據庫代碼,對吧? – Pascal 2011-02-24 23:39:30

+0

@Pascal - 正確。那有什麼問題?每個對象的一組CRUD procs。這樣你可以讓他們分開。 ATM你有一種方法使用每一個對象。 – RPM1984 2011-02-25 00:46:46

+0

@ RPM194現在我明白你的意思了......但是我的課程是Helper Classes,它將無聊的東西集中到實際運行特定/查詢中。我非常感謝您的意見,以及您提出建議的時間,這是一個好主意,但它不符合我目前的需要。但是,謝謝。 – Pascal 2011-02-25 00:56:33