将SqlCommand转换为T-SQL命令

Hei*_*nzi 3 c# vb.net sql-server ado.net

我有一个SqlCommand参数.由于一些外部要求(参见PS),我需要一个T-SQL字符串,即我需要... @parameter ... 替换为... the-value-of-@parameter-encoded-correctly ...(例如O'Brien- > 'O''Brien',02 Mar 2010- > '20100302',3.5- > 3.5).

我知道我可以很容易地在家中酿造这样的解决方案,但正确的转义是棘手的(确保你得到正确的日期和数字格式,注意字符串中的引号等),我想我不是唯一需要这个,所以我的问题是:

是否存在将带参数的SqlCommand转换为嵌入并正确转义参数的单个T-SQL语句的现有解决方案?

PS:我们需要这样做,因为我们需要使用SqlCommandMS Access报告的数据源......并且Access中的"pass-through querydefs"不支持参数化SQL.

PPS:我知道有类似的 问题,但他们都假设SQL Server以某种方式进行了这种转换(@parameter- >一些表示值的转义字符串),所以答案("SQL Server不这样做")不适用这里.我知道SQL Server中没有发生这种转换.

Jam*_*nne 5

我认为用参数写出SQL查询DECLARE @p1 type;SET @p1 = 'value';在主SELECT查询之前有一些和几行,并SqlCommand保持实例中的原始查询文本不变,这一点要清楚得多.我有一些示例代码可以执行此操作,如果您想看到它.

如果您真的坚持在查询文本中简单地进行参数值替换,那么找一个特定于您正在与之交谈的服务器的T-SQL语法,解析查询直到找到参数引用,并将其替换为文本根据T-SQL语法的字符串转义规则.

编辑:

因为我是一个非常棒的家伙,所以我会让你开始通过适当的转义来格式化输出的SQL参数.这是非常不完整的,因为它不处理man和SQL Server已知的每一种数据库类型,但它完成了我的工作,因为它处理我最常用的类型.正如我在评论中所说的那样,简单地将单引号字符转义为连续的两个单引号字符似乎足以进行正确的字符串值转义.您必须对各种SQL Server版本使用的T-SQL语法进行双重和三重检查,以确保它足够好.

private static string FormatSqlValue(System.Data.Common.DbParameter prm)
{
    if (prm.Value == DBNull.Value) return "NULL";
    switch (prm.DbType)
    {
        case System.Data.DbType.Int32: return (prm.Value.ToString());
        case System.Data.DbType.String: return String.Format("'{0}'", ScrubSqlString((string)prm.Value));
        case System.Data.DbType.AnsiString: return String.Format("'{0}'", ScrubSqlString((string)prm.Value));
        case System.Data.DbType.Boolean: return ((bool)prm.Value ? "1" : "0");
        case System.Data.DbType.DateTime: return String.Format("'{0}'", prm.Value.ToString());
        case System.Data.DbType.DateTime2: return String.Format("'{0}'", prm.Value.ToString());
        case System.Data.DbType.Decimal: return (prm.Value.ToString());
        case System.Data.DbType.Guid: return String.Format("'{0}'", prm.Value.ToString());
        case System.Data.DbType.Double: return (prm.Value.ToString());
        case System.Data.DbType.Byte: return (prm.Value.ToString());
        // TODO: more conversions.
        default: return (prm.DbType.ToString());
    }
}

private static string FormatSqlValue(Type type, object value)
{
    if (value == null)
        return "NULL";
    // Handle Nullable<T> types:
    if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
    {
        // If the Nullabe<T> value has been found to have !HasValue, return "NULL":
        if (!(bool)type.GetProperty("HasValue").GetValue(value, null))
            return "NULL";
        // Try our best to format the underlying non-nullable value now:
        return FormatSqlValue(type.GetGenericArguments()[0], type.GetProperty("Value").GetValue(value, null));
    }
    if (type == typeof(Int32)) return value.ToString();
    if (type == typeof(String)) return String.Format("'{0}'", ScrubSqlString((string)value));
    if (type == typeof(Boolean)) return ((bool)value ? "1" : "0");
    if (type == typeof(DateTime)) return String.Format("'{0}'", value.ToString());
    if (type == typeof(Decimal)) return (value.ToString());
    if (type == typeof(Guid)) return String.Format("'{0}'", value.ToString());
    if (type == typeof(Double)) return (value.ToString());
    if (type == typeof(Byte)) return (value.ToString());
    // TODO: complete the mapping...
    return value.ToString();
}

private static string ScrubSqlString(string value)
{
    StringBuilder sb = new StringBuilder();
    int i = 0;
    while (i < value.Length)
    {
        if (value[i] == '\'')
        {
            sb.Append("\'\'");
            ++i;
        }
        else
        {
            sb.Append(value[i]);
            ++i;
        }
    }
    return sb.ToString();
}

private static string FormatSqlParameter(System.Data.Common.DbParameter prm)
{
    StringBuilder sbDecl = new StringBuilder();
    sbDecl.Append(prm.ParameterName);
    sbDecl.Append(' ');
    switch (prm.DbType)
    {
        case System.Data.DbType.Int32: sbDecl.Append("int"); break;
        // SQL does not like defining nvarchar(0).
        case System.Data.DbType.String: sbDecl.AppendFormat("nvarchar({0})", prm.Size == -1 ? "max" : prm.Size == 0 ? "1" : prm.Size.ToString()); break;
        // SQL does not like defining varchar(0).
        case System.Data.DbType.AnsiString: sbDecl.AppendFormat("varchar({0})", prm.Size == -1 ? "max" : prm.Size == 0 ? "1" : prm.Size.ToString()); break;
        case System.Data.DbType.Boolean: sbDecl.Append("bit"); break;
        case System.Data.DbType.DateTime: sbDecl.Append("datetime"); break;
        case System.Data.DbType.DateTime2: sbDecl.Append("datetime2"); break;
        case System.Data.DbType.Decimal: sbDecl.Append("decimal"); break;  // FIXME: no precision info in DbParameter!
        case System.Data.DbType.Guid: sbDecl.Append("uniqueidentifier"); break;
        case System.Data.DbType.Double: sbDecl.Append("double"); break;
        case System.Data.DbType.Byte: sbDecl.Append("tinyint"); break;
        // TODO: more conversions.
        default: sbDecl.Append(prm.DbType.ToString()); break;
    }
    return sbDecl.ToString();
}
Run Code Online (Sandbox Code Playgroud)