0

私は、通常のように機能する SQLFormat 関数に取り組んでいます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(すでにそのパラメーターを追加しているため)

これがフォーマットを行う私のクラスです。現在、インデックス作成に static int を使用しています

現在のパラメーター インデックスを取得できるかどうかはわかりません)。

1 つの方法は、フォーマットをスキップすることですが、これが必要なので、自分でトークンを置き換えることをスキップできます。(私String.Formatが生成できるコードよりも速いと思います:P)

UPDATED : 現在のコードでコードを更新しました。事前にすべてのトークンを準備し、パラメーター名を値ではなく値としてプッシュします。

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この場合。

4

3 に答える 3

1

まず、スペースを含む文字列は空と見なされないためstring.IsNullOrEmpty、 を使用せず、 に置き換えます。string.IsNullOrWhiteSpace

第 2 に、パラメーターをこのように使用するべきではありません。これは、SQL インジェクションが発生する可能性があるセキュリティ上の問題です。代わりに、パラメーター オブジェクトをコマンドに追加してください。

第 3 に、パラメーター オブジェクトを使用すると、名前付きパラメーターを使用する限り、同じパラメーターを 2 回再利用できます。

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.
}

免責事項

私の頭の上からコンパイルされていないコードサンプル。例としてのみ現状のまま提供されます。

于 2014-04-08T18:43:23.777 に答える
1

あなたの例を見て、ここでそれを実行することは、私が前に見たことのないものについての興味深い教訓だったので、私は完全にオフになっているかもしれません..

挿入するプレースホルダーのインデックスが好きに見えます0{0:フォーマットには常に 1 つの値しかないため、常に0.

内部の (静的ではない!) int は明らかにナンセンスです。また、現在のインデックスを取得したいという考えも間違っているようです。

私にとっての解決策は、名前だけでなく、数字と名前の 2 つの値を実際に提供することです。構文についてはお手伝いできません。または、名前から数字を差し引いたほうがいいと思います。

すでに辞書に載っている名前に出会うたびに、辞書を作成してそこから番号を引き出すことができます。他の名前は、増分された番号で追加されます。

ここに簡単なものがあります。動作するようです..:

    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);
        }
于 2014-04-08T18:29:16.897 に答える