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(因为我已经添加了那个参数)

这是我的格式化课程。目前我正在使用静态 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在这种情况下。

4

3 回答 3

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

免责声明

代码示例不是从我的脑海中编译出来的。按原样提供仅用于示例目的。

于 2014-04-08T18:43:23.777 回答
0

这是一般 SQL 库的标准行为。该库不知道您将始终对第一个和第三个参数使用相同的值。

于 2014-04-08T18:51:37.877 回答