2009-02-23 140 views
18

我可能會負責將vb6應用程序移植到c#。此應用程序是一個Windows應用程序,與訪問數據庫交互。數據訪問被封裝在基本業務對象中。基本上是一個表的一個類。現有的vb6業務對象通過DAO讀取和寫入數據庫。我之前幾次編寫過DAL和ORM,但它們都只針對SQL Server。這將需要目標訪問和SQL Server。在以前的項目中,我會將SQL字符串放在業務對象的私有部分中,並可能將冗餘SQL代碼(如連接,創建命令)移入公共基類以減少代碼。你在哪裏把SQL語句放到你的C#項目中?

這一次,我正在考慮將SQL字符串寫入.settings文件或其他鍵/值類型的文本文件。然後,我會編寫一個sql工具來編輯這個文件,並允許我運行和測試參數化查詢。這些查詢將在業務對象中被名稱引用,而不是將sql嵌入到代碼中。

我知道一個標準的方法是爲每個目標數據庫創建一個DAL,並擁有DAL使用的配置狀態。我真的不想爲每個數據庫創建兩個DAL類。如果我只是通過keyname引用了正確的查詢並且具有適當的連接類型,那麼它看起來好像會少一些代碼。

那麼,你們是否在做這樣的事情?你會如何處理這個問題? 什麼最適合你?

謝謝!

回答

24

嗯,有很多的選擇 - 所以這真的取決於你的最迫切的需求是什麼:-)

一種方法可能是在VS解決方案中將SQL語句創建爲文本文件,並將其標記爲「構建操作」中的「嵌入式資源」。這樣一來,SQL包含在您得到的組件,並且可以從它在運行時使用.NET框架的ResourceManifestStream檢索:

private string LoadSQLStatement(string statementName) 
{ 
    string sqlStatement = string.Empty; 

    string namespacePart = "ConsoleApplication1"; 
    string resourceName = namespacePart + "." + statementName; 

    using(Stream stm = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName)) 
    { 
     if (stm != null) 
     { 
      sqlStatement = new StreamReader(stm).ReadToEnd(); 
     } 
    } 

    return sqlStatement; 
} 

你需要與你的實際命名空間,以取代「ConsoleApplication1」,其中sql語句文件駐留。您需要通過完全限定的名稱來引用它們。

string mySQLStatement = LoadSQLStatement("MySQLStatement.sql"); 

然而,這使得查詢,而「靜」,例如:然後你就可以使用此行載入你的SQL語句你不能在運行時配置和修改它們,它們會被編譯進二進制位。但另一方面,在VS中,你的C#程序代碼和SQL語句之間有很好的分離。

如果您需要能夠在運行時調整和更改它們,我會將它們放入一個包含例如關鍵字和實際的SQL查詢作爲字段。然後您可以根據需要檢索它們,並執行它們。由於它們在數據庫表中,因此您也可以隨意更改,修改和修改它們 - 即使在運行時也可以 - 無需重新部署整個應用程序。

馬克

+1

我已經使用了這種方法,我喜歡它。與大多數人不同,我不同意在運行時即時更改代碼,即使是簡單的SQL語句,所以使用程序集進行編譯這一事實對我來說是一個很好的補充。 – Chris 2009-03-08 16:25:17

+1

很高興聽到這種方法正在被其他人使用和歡迎! :-)我同意 - 有時將東西烘焙到您的編譯位中是一件好事。 – 2009-03-08 17:34:48

1

我會告訴我哪裏不會放它,我看到我在繼承的一些代碼中完成的東西。這是在Java中,但適用於任何語言

  • 一個基類,聲明爲受保護的靜態成員變量的SQL語句,inited爲null,與返回get方法單個SQL語句

  • 一子類爲每個支持的數據庫服務器,與分配給基類成員變量

  • 若干DA類,使用基類方法來檢索SQL語句的init方法

  • 與責任的應用程序啓動類來創建正確的子類的對象,並調用它的init方法

我也不會去解釋爲什麼我不會做這個不斷:-)

+2

面向對象的純粹語言導致這樣的OO噩夢!滑稽! – Steve 2009-02-23 16:57:50

1

我們使用的一種方法是擁有一個可連接到數據庫的類和調用過程的方法,並在方法參數中提供過程名稱。所以所有的SQL代碼都在這個過程中。我們將使用重載的返回類型不同

class ConnectToSQL() 
{ 
     //connectSql code (read from setting file i assume) 

     XMLDataDocument runProcedure(string procedureName); 
     int runProcedure(string procedureName); 

     //etc.... 
} 
+0

你不能有隻有返回類型不同的重載 - 它會給編譯器一個錯誤CS0111 – MattDavey 2017-08-21 16:11:31

2

LINQ到DataSet中聽起來像去你的方式。

如果你還沒有在/ LINQ之前使用過.NET 3.5,那麼你需要一個享受。 LINQ將節省您在字符串文字中編寫原始SQL,併爲您提供創建查詢的更合乎邏輯的方法。

無論如何,檢查此鏈接了對Access數據庫使用LINQ - http://msdn.microsoft.com/en-us/library/bb386977.aspx

9

當我真的需要它,我把查詢到單個* .sql文件,然後將它們包括到Resources.resx。有一個'文件'部分,它允許你包含嵌入式資源文件。

之後,我可以使用生成的Resources.MyQuery屬性,這兩個屬性都可以確保資源的存在並使我無法編寫自定義資源加載方法。

1

如果我不得不爲SQL和Access創建應用程序,我會使用一些IDAL接口,DALCommon和通用功能實現,以及從DALCommon繼承的單獨的DALSql和DALAccess,以及一些特定的東西,例如異常,事務處理,安全等
我用來保存資源文件中的存儲過程名稱或查詢。

0

有時,與自定義報告應用程序一樣,您確實需要擁抱阻抗不匹配,並且對SQL特別重要。在這些情況下,我建議如下:對於每個包含SQL字符串的模塊,創建一個靜態「SQL」類來保存它們全部。某些SQL字符串可能需要參數,因此要保持一致並將每個字符串放在它自己的靜態方法後面。

我只對偶爾的自定義報告應用程序這樣做,但它始終工作得很好,感覺清爽和解放。在幾個月後回來進行增強,並且在單個SQL.cs文件中查找所有等待您的SQL是非常好的。只需讀取一個文件,它就會全部返回,並且通常這是唯一需要更改的文件。

我沒有看到在這些情況下需要隱藏資源或其他地方的SQL。當SQL很重要時,那很重要。有趣的是,越來越多的開發者現在可以自由地將SQL與C#混合在一起,包括我相信這個網站,因爲從本質上講,這就是LINQ。

最後,一如既往,確保您不容易受到SQL注入攻擊。特別是如果涉及用戶輸入,請確保您使用某種參數化,並且您沒有使用字符串連接。

0

上面顯示的嵌入解決方案可能無法工作,如果SQL查詢具有「where」原因,但對於相同的查詢,隨着PropertyID被讀入,下一次運行需要PropertyID ='113'。

0

Glad you asked! Put your sql in a QueryFirst .sql template.

它會自動編譯到您的應用程序作爲嵌入資源,但你不在乎。您只需在一個真正的SQL窗口中將其寫入數據庫,然後使用表格和列的語法驗證和智能感知,然後通過生成的Execute()方法將其用於輸入和結果的智能感知。

免責聲明:我寫了QueryFirst。