[C#]仿LINQ實作支援異質資料庫來源(未完成)

[C#]仿LINQ實作支援異質資料庫來源

猶記得數年前LINQ還不風行時,一套系統要支援多種資料庫語法,對系統開發人員來說真的是個蠻可怕的噩夢,因為SQL/Oracle的語法、保留字等等都不完全相同,如果在加上其他的資料庫來攪局,系統存取資料庫的SQL要怎麼寫才對?當初常被拿來使用的做法有好幾個:

1.ANSI SQL(使用標準的SQL寫法)

2.用IF或Switch case來切換不同的SQL語法(if(SQL){…}eles if(Oracle){…}else{…})

2.的解法絕對不夠漂亮,因為需要寫多份SQL,在維護時真的挺累人的,因為要同時修改每種資料庫型態的SQL指令,那1.呢?ANSI SQL由於是標準寫法,導致部分資料庫系統特有的好用function會變得無法使用,如果你的客群有80%是落於SQL Server上,那你是否要為了那20%的客戶放棄SQL Server本身提供的好功能呢?見仁見智了。

另外,由於一套系統的AP會由好多人開發,每個人對SQL語法的掌握度不盡相同,有些人寫出來的SQL語法很漂亮,執行效率又高,有些人則沒有這份功力,寫出來的指令可能還有SQL Injection,當初丟出另一個問題,能不能讓開發AP的這些Programmer對SQL語法的進入門檻降低?

不過基於以上兩個原因,當初我們做了一些發想,發想的主題是:一句SQL,同時滿足兩個願望。

思前想後,突然靈光一閃,我們可不可能透過物件的控制來達到此功能,比如Programmer可以執行以下的指令自動組出完整的SQL,而由QueryObj這個物件來處理不同的SQL指令間的差別,如此我們可以不用在每一段程式中寫if/else來判斷要執行哪段SQL,也同時可以降低Programmer對SQL語法的進入門檻,下方的用法看起來也蠻直覺式的:


QueryObj.Select("*").From("Table").Where("A", "123");

後來開始動工寫了一些小範例,當初的完整寫法我不記得了,下面我依相同概念隨便寫一下:


    public class QueryObj
    {
        public QueryObj() { }

        public string gSQLCommand;

        public QueryObj Select(string pTable, string pFields)
        {
            this.gSQLCommand += "SELECT " + pFields +" FROM " + pTable;
            return this;
        }

        public QueryObj Where(string pWhere)
        {
            this.gSQLCommand += " WHERE " + pWhere;
            return this;
        }

        public QueryObj LeftJoin(string pTable, string pColumn1, string pColumn2)
        {
            this.gSQLCommand += " LEFT JOIN " + pTable + " ON " + pColumn1 + "=" + pColumn2;
            return this;
        }

        public override string ToString()
        {
            return gSQLCommand;
        } }

重點在每個function都是回傳OueryObj本身,所以我們在另一個呼叫的程式段我們可以這樣寫:


        public string AppendCommand()
        {
            QueryObj tQueryObj = new QueryObj();
            string tCommand = tQueryObj.Select("Products", "*").
                LeftJoin("Orders", "Products.ID", "Orders.ID").
                Where("ProductName='DELL'").ToString();
            return tCommand;
        }

因為每個function都是回傳QueryObj,所以我也可以繼續使用QueryObj這個Class的所有member,這段程式最後組出來的結果是:

 


SELECT * FROM Products LEFT JOIN Orders ON Products.ID=Orders.ID

 

看起來非常好阿,我只要在QueryObj這個Class中處理所有的異質資料庫SQL指令就好,那為什麼最後我們還是沒有執行這項工作呢?原因有二:

1.要涵蓋全部的SQL語法幾乎是天方夜譚(CASE/子查詢...)

2.Programmer要學會用這個QueryObj說不定更耗功夫

唯一省下來的工作量就是後續維護時比較方便,雖然最後沒有向下延伸,不過這也算是當初一個很有趣的發想。

游舒帆 (gipi)

探索原力Co-founder,曾任TutorABC協理與鼎新電腦總監,並曾獲選兩屆微軟最有價值專家 ( MVP ),離開職場後創辦探索原力,致力於協助青少年培養面對未來的能力。認為教育與組織育才其實息息相關,都是在為未來儲備能量,2018年起成立為期一年的專題課程《職涯躍升的關鍵24堂課》,為培養台灣未來的領袖而努力。