2014-04-08 56 views
0

我正在使用SQLFormat函數,它的工作方式與正常的String.Format類似。當前索引在自定義String.Format中

現在我卡在正對這些指標目前Format是依賴。

例如,我們有這樣的SQL查詢(的僞,不是實際使用)。

SELECT * 
FROM users 
WHERE userID = {0:SQL;userID} 
AND 10 != {1:SQL;strangeID} 
AND 100 = {0:SQL;userID} 

這是格式化像現在這樣的權利:

SELECT * 
FROM users 
WHERE userID = @p0 /* userID */ 
AND 10 != @p1 /* strangeID */ 
AND 100 = @p2 /* userID */ 

凡輸出@p2,我希望它重用@p0(因爲我已經加入該參數)

這裏是我的類的格式。目前,我正在使用靜態int進行索引

我還沒有發現如果我可以得到當前的參數索引)。

一種方法是跳過格式化,但我需要這個,所以我可以跳過自己替換標記。 (我認爲這String.Format比代碼我可能會產生更快的:P)

修訂:我與我當前的代碼更新的代碼,我準備在事先所有的令牌,並在參數名推的值,而不是的價值。

public class SqlFormat : IFormatProvider, ICustomFormatter 
{ 
    public object GetFormat(Type formatType) 
    { 
     if (formatType == typeof(ICustomFormatter)) 
      return this; 
     return null; 
    } 

    internal int IndexCounter = 0; 
    Dictionary<string, int> dict = new Dictionary<string, int>(); 

    public string Format(string format, object arg, IFormatProvider formatProvider) 
    { 
     if (!this.Equals(formatProvider)) 
      return null; 
     if (string.IsNullOrWhiteSpace(format)) 
      format = "SQL;field"; 

     var formats = format.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); 
     format = formats[0]; 

     if (format == "SQL") 
     { 
      string ind = IndexCounter.ToString(); 
      if (dict.ContainsKey(formats[1])) ind = dict[formats[1]].ToString(); 
      else dict.Add(formats[1], IndexCounter++); 
      var pName = arg; 
      return pName + (formats.Length > 1 ? " /* " + formats[1] + " */" : ""); 
     } 
     else 
     { 
      return HandleOtherFormats(format, arg); 
     } 
    } 

    public string HandleOtherFormats(string format, object arg) 
    { 
     return string.Format(format, arg); 
    } 
} 

用法示例:

var sql = @"SELECT {0:SQL;userID}, {0:SQL;userID}"; 

var retSql = String.Format(new SqlFormat(), sql, new[] { 650 }); 
Console.WriteLine(retSql); 

這將返回SELECT @p0 /* userID */, @p1 /* userID */

代替

SELECT @p0 /* userID */, @p0 /* userID */

有一些辦法,我可以得到當前的指數? 0在這種情況下。

回答

1

看你的例子並運行它在這裏是有關的東西我從來沒有見過一個有趣的課,所以我可能會完全關閉..

0{0:看起來像我的索引插入的佔位符。你的格式總是隻有一個值,所以它會一直使用,只需要一個0

內部(不是靜態!)int顯然是無稽之談。而且你想得到當前指數的想法也是錯誤的。

對我來說,解決方案將是你實際上提供了兩個值,數字和名稱不只是名稱。無法幫助你的語法。或者,那會更好,我認爲,你從名稱中扣除數字。

您可以構建一個字典並從中獲取數字,只要您遇到字典中已有的名稱。其他名稱會添加一個遞增的數字。

這是一個快速的;似乎工作..:

public class SqlFormat : IFormatProvider, ICustomFormatter 
    { 
     public object GetFormat(Type formatType) 
     { 
      if (formatType == typeof(ICustomFormatter)) 
       return this; 
      return null; 
     } 

     internal int IndexCounter = 0; 
     Dictionary<string, int> dict = new Dictionary<string, int>(); 

     public string Format(string format, object arg, IFormatProvider formatProvider) 
     { 
      if (!this.Equals(formatProvider)) 
       return null; 

      if (string.IsNullOrEmpty(format)) 
       format = "SQL"; 

      var formats = format.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); 
      format = formats[0]; 

      if (format == "SQL") 
      { 

       string ind = IndexCounter.ToString(); 
       if (dict.ContainsKey(formats[1])) ind = dict[formats[1]].ToString(); 
       else dict.Add(formats[1], IndexCounter++); 
       var pName = "@p" + ind; 

       return pName + (formats.Length > 1 ? " /* " + formats[1] + " */" : ""); 
      } 
      else 
      { 
       return HandleOtherFormats(format, arg); 
      } 
     } 

     public string HandleOtherFormats(string format, object arg) 
     { 
      return string.Format(format, arg); 
     } 
+0

太棒了,有了這個我有一些工作。我只是要修改它,所以我可以處理非命名標記。非常感謝! – NoLifeKing

+0

好;有幾件事情需要考慮,例如在另一個答案中也是安全的.. – TaW

+0

是的,我把所有東西都放到了SqlParameters中,以確保我擺脫了注入風險等等。 :) – NoLifeKing

1

首先,你不得使用string.IsNullOrEmpty,與string.IsNullOrWhiteSpace取代它,因爲包含空格不會被視爲空字符串。其次,你不應該像你這樣使用參數,這是SQL注入可能發生的安全問題。相反,將參數對象添加到您的命令。

第三,使用參數對象,只要使用命名參數,就可以重複使用相同的參數兩次。

using (var cnx = new SqlConnection(connectionString)) { 
    cnx.Open(); 

    var cmd = cnx.CreateCommand(); 
    cmd.CommandText = sql; // sql is actually your string containing named-parameters 
    var param1 = cmd.CreateParameter(); 
    param1.DbType = DbType.Int32; 
    param1.ParameterDirection = ParameterDirection.Input; 
    param1.Name = "@p0"; 
    param1.Value = value; 

    cmd.ExecuteQuery(); // Make sure to use proper method call here. 
} 

免責聲明

代碼示例不是編出來我的頭頂部。僅用於舉例目的。

+0

改爲使用'string.IsNullOrWhiteSpace'代替我的代碼。 ^^ – NoLifeKing

0

這是一般的SQL庫的標準行爲。庫不知道你會總是使用相同的值爲第一和第三個參數。

+2

現在這個答案是一個很好的介紹,以實際解決問題的答案。請更新。 – AndyG