不知天生粗枝大葉還是怎樣,每回只要操作大量欄位Table的新增修改,我總會迷失在茫茫的Parameter大海中...(這也解釋了為什麼我愛死了LINQ to SQL/LINQ to Oracle)

複雜的資料表有三四十個欄位是家常便飯,CommandText就得宣告三四十個參數名稱,然後照著這堆參數名稱一一Parameters.Add,只要名稱打錯或多一個少一個,就會冒出"ORA-01036 illegal variable name/number 變數名稱/號碼無效"之類的錯誤,通知我練眼力的時間到了! 此時別無他法,只能逐一檢查有無打錯字,多參數少參數的。動轍要核對三四十個參數名稱,對耐性欠佳的我是種折磨,偶爾甚至會有輕生的念頭...

為了避免自己常陷入性命攸關的危機,我寫了一個工具函數來幫忙檢核。如以下的範例,一旦Parameter數目、名稱與CommandText中的宣告對不上,就會得到警告:

System.Data.OracleClient.OracleCommand cmd = 
    new System.Data.OracleClient.OracleCommand();
cmd.CommandText = "insert into pack values (:v_id, :v_name, :v_count)";
cmd.Parameters.Add("v_name", OracleType.VarChar).Value = "Item1";
cmd.Parameters.Add("v_id", OracleType.Number).Value = 1;
//cmd.Parameters.Add("v_count", OracleType.Number).Value = 100;
cmd.Parameters.Add("v_wtf", OracleType.VarChar).Value = "WTF";
string result = DbJobHelper.VerifyCommandParameters(cmd, ":v_", false);
Response.Write(result);

結果為: Parameter[v_wtf]-not used! Parameter[:v_count]-missing!

另外,函數還提供了reorder的功能,讓Parameter可以依其在CommandText裡的出場順序重新排列。

程式碼如下,需要的朋友請自取:

    /// <summary>
    /// IDbCommand.Parameters檢核,找出Parameters數目不合問題
    /// </summary>
    /// <param name="cmd">IDbCommand物件</param>
    /// <param name="prefix">CommandText中的參數名特徵,如:v_, @p_</param>
    /// <param name="reorder">是否重新依參數出場順序排序</param>
    /// <returns></returns>
    public static string VerifyCommandParameters(
        IDbCommand cmd, string prefix, bool reorder)
    {
        Dictionary<string, string> paramSymbolCheck = 
            new Dictionary<string, string>();
        Dictionary<string, string> paramUsageCheck = 
            new Dictionary<string, string>();
        Dictionary<string, IDataParameter> paramPool = 
            new Dictionary<string, IDataParameter>();
        List<string> paramOrder = new List<string>();
        string s = "";
        for (int i = 0; i < prefix.Length; i++)
            s += "[" + prefix.Substring(i, 1) + "]";
        //用RegEx找出CommandText中的參數宣告
        foreach (Match m in Regex.Matches(cmd.CommandText,
            "(?ims)(?<n>" + s + "[a-zA-Z0-9_]+)"))
        {
            //OracleParameter要去掉前方的:才是ParameterName
            string pn = m.Value.ToUpper().TrimStart(':');
            paramSymbolCheck.Add(pn, m.Value);
            paramOrder.Add(pn);
        }
        //找出所有參數物件
        foreach (IDataParameter p in cmd.Parameters)
        {
            paramUsageCheck.Add(p.ParameterName.ToUpper(), 
                p.ParameterName);
            paramPool.Add(p.ParameterName.ToUpper(), p);
        }
        StringBuilder sb = new StringBuilder();
        //檢查是否每個Parameter都有被用到?
        foreach (string n in paramUsageCheck.Keys)
        {
            if (!paramSymbolCheck.ContainsKey(n))
                sb.AppendFormat("Parameter[{0}]-not used!\n", 
                    paramUsageCheck[n]);
        }
        //檢查是否每個參數宣告都有對應的Parameter?
        foreach (string n in paramSymbolCheck.Keys)
        {
            if (!paramUsageCheck.ContainsKey(n))
                sb.AppendFormat("Parameter[{0}]-missing!\n", 
                    paramSymbolCheck[n]);
        }
        //依出現順序重排參數
        if (sb.Length == 0 && reorder)
        {
            cmd.Parameters.Clear();
            foreach (string n in paramOrder)
                cmd.Parameters.Add(paramPool[n]);
        }
        return sb.ToString();
    }

Comments

# by White Cloud

何不把檢查乾脆改為程式自動產生那堆 Parameters.Add 相關的敘述,再把產生出的東西貼回就好囉 這個方法也可適用於自動產生一些類似但只是欄位名稱不同而已的情況,當然可能欄位處理會有文字數字是否需加上括弧之類的狀況,不過可以大量減少重覆的核對工作 環境許可的話, 以前我都用 shell 來輔助這種動作

# by kennyshu

我能體會那種痛苦,之前要更新一堆Oracle的fields,有時候真的多打了一個點(.),然後要從錯誤訊息裡面找出那一個"點"真的會耗光時間和耐心...

Post a comment