C# 将SqlCommand转换为T-SQL命令

C# 将SqlCommand转换为T-SQL命令,c#,sql-server,vb.net,ado.net,C#,Sql Server,Vb.net,Ado.net,我有一个带有参数的SqlCommand。由于一些外部要求(参见PS),我需要一个T-SQL字符串,即我需要@参数…替换为。。。-@参数的值已正确编码…(例如,O'Brien-->'O'Brien',2010年3月2日-->'20100302',3.5-->3.5) 我知道我可以很容易地自制这样一个解决方案,但正确的转义是很棘手的(确保您获得正确的日期和数字格式,注意字符串中的引号,等等),我想我不是唯一需要这个的人,所以我的问题是: 是否有一种现有的解决方案可以将带有参数的SqlCommand转

我有一个带有参数的
SqlCommand
。由于一些外部要求(参见PS),我需要一个T-SQL字符串,即我需要
@参数…
替换为
。。。-@参数的值已正确编码…
(例如,
O'Brien
-->
'O'Brien'
2010年3月2日
-->
'20100302'
3.5
-->
3.5

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

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

PS:我们需要这样做,因为我们需要使用
SqlCommand
作为MS Access报告的数据源。。。Access中的“传递querydefs”不支持参数化SQL


PPS:我知道有,但它们都假设SQL Server以某种方式进行了这种转换(
@parameter
-->一些表示值的转义字符串),因此答案(“SQL Server不这样做”)不适用于这里。我知道SQL Server中没有发生这种转换。

我认为编写带有参数的SQL查询并使用一些
声明@p1类型要清楚得多
SET@p1='value'行”,并保持
SqlCommand
实例中的原始查询文本不变。我有一些示例代码,如果您愿意的话,可以这样做

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

编辑

由于我是一个非常棒的人,我将让您开始使用正确的转义来格式化输出的SQL参数。这是非常不完整的,因为它不能处理man和SQL Server已知的每一种数据库类型,但它为我完成了这项工作,因为它可以处理我最常用的类型。正如我在评论中所说,简单地将单引号字符作为连续的两个单引号字符进行转义似乎就足以实现正确的字符串值转义。您必须对各种SQLServer版本使用的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();
}
私有静态字符串FormatSqlValue(System.Data.Common.DbParameter prm)
{
如果(prm.Value==DBNull.Value)返回“NULL”;
开关(prm.DbType)
{
case System.Data.DbType.Int32:return(prm.Value.ToString());
case System.Data.DbType.String:返回String.Format(“{0}”,ScrubSqlString((String)prm.Value));
case System.Data.DbType.AnsiString:返回String.Format(“{0}”,ScrubSqlString((String)prm.Value));
case System.Data.DbType.Boolean:返回((bool)prm.Value?“1”:“0”);
case System.Data.DbType.DateTime:返回String.Format(“{0}”,prm.Value.ToString());
case System.Data.DbType.DateTime2:返回String.Format(“{0}”,prm.Value.ToString());
case System.Data.DbType.Decimal:return(prm.Value.ToString());
case System.Data.DbType.Guid:返回String.Format(“{0}”,prm.Value.ToString());
case System.Data.DbType.Double:return(prm.Value.ToString());
case System.Data.DbType.Byte:返回(prm.Value.ToString());
//TODO:更多转换。
默认值:return(prm.DbType.ToString());
}
}
私有静态字符串FormatSqlValue(类型、对象值)
{
如果(值==null)
返回“NULL”;
//处理可为空的类型:
if(type.IsGenericType&&type.GetGenericTypeDefinition()==typeof(可为空))
{
//如果发现Nullabe值具有!HasValue,则返回“NULL”:
if(!(bool)type.GetProperty(“HasValue”).GetValue(value,null))
返回“NULL”;
//现在请尽力格式化基础的不可为空值:
返回FormatSqlValue(type.GetGenericArguments()[0],type.GetProperty(“Value”).GetValue(Value,null));
}
if(type==typeof(Int32))返回值.ToString();
if(type==typeof(String))返回String.Format(“{0}”,ScrubSqlString((String)value));
if(type==typeof(Boolean))返回((bool)值?“1”:“0”);
if(type==typeof(DateTime))返回String.Format(“{0}”,value.ToString());
if(type==typeof(Decimal))返回(value.ToString());
if(type==typeof(Guid))返回String.Format(“{0}”,value.ToString());
if(type==typeof(Double))返回(value.ToString());
if(type==typeof(Byte))返回(value.ToString());
//TODO:完成映射。。。
返回值.ToString();
}
私有静态字符串ScrubSqlString(字符串值)
{
StringBuilder sb=新的StringBuilder();
int i=0;
while(i