如何检索给定的StoredProcedure在SQL参数.NET类型? [英] How to retrieve .NET type of given StoredProcedure's Parameter in SQL?

查看:100
本文介绍了如何检索给定的StoredProcedure在SQL参数.NET类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建上面的SQL程序通用的包装,我可以解决所有必需的参数的名字和的SQLType,但有什么办法如何得到它的潜在的'.NET类型?



我的目标是做这样的事情:

 的SqlParameter参数; 
对象的值;
对象correctParam = param.GetNETType()实现getMethod(解析,
新型[] {typeof运算(字符串)})调用(value.ToString())。;
param.Value = correctParam;



在哪里GetNETType是我需要的东西。
口知道,它可以写为param.SqlDbType的内部开关,但这是较短方式,更短的注释的代码意味着更低mainteance:)


解决方案

不幸的是,据我所知,这个映射是不是在.NET Framework内部代码暴露出来。我已经通过之前,此.NET框架参考源望去,发现在.NET代码中有很多长按式开关语句,就像你试图避免的,但他们都不在外部露出。



如果你真的只是想从的SQLType最likley .NET类型映射,我想你最好的选择是简单地把映射表的在MSDN文档成代码。需要注意的是MSDN上的表有(至少)两个错误:#1:不存在所谓的DATETIME2.NET类型(我用的日期时间),而且也没有类型,称为XML(我用的SQLXML)

总之,这里是我一直在使用一个字典,而不是为四通八达的交通网络交换机没有一个单独的方法using--的映射。

 公共静态字典< SqlDbType,类型>的TypeMap =新词典< SqlDbType,类型> 
{
{SqlDbType.BigInt的typeof(Int64的)},
{SqlDbType.Binary的typeof(字节[])},
{SqlDbType.Bit的typeof(布尔) }
{SqlDbType.Char的typeof(字符串)},
{SqlDbType.Date的typeof(DateTime的)},
{SqlDbType.DateTime的typeof(DateTime的)},
{SqlDbType.DateTime2的typeof(DateTime的)},
{SqlDbType.DateTimeOffset的typeof(的DateTimeOffset)},
{SqlDbType.Decimal的typeof(十进制)},
{SqlDbType.Float的typeof(双人间)},
{SqlDbType.Int的typeof(Int32)已}
{SqlDbType.Money的typeof(十进制)},
{SqlDbType.NChar的typeof(字符串) }
{SqlDbType.NText的typeof(字符串)},
{SqlDbType.NVarChar的typeof(字符串)},
{SqlDbType.Real的typeof(单人间)},
{SqlDbType.SmallInt的typeof(Int16的)},
{SqlDbType.SmallMoney的typeof(十进制)},
{SqlDbType.Structured的typeof(对象)} //可能不是最好的映射。 ..
{SqlDbType.Text的typeof(字符串)},
{SqlDbType.Time的typeof(时间跨度)},
{SqlDbType.Timestamp的typeof(字节[])}
{SqlDbType.TinyInt的typeof(字节)},
{SqlDbType.Udt的typeof(对象)} //未必是最好的映射......
{SqlDbType.UniqueIdentifier的typeof( GUID)},
{SqlDbType.VarBinary的typeof(字节[])},
{SqlDbType.VarChar的typeof(字符串)},
{SqlDbType.Variant的typeof(对象)} ,
{SqlDbType.Xml的typeof(SQLXML)},
};

请注意一件事情,就是你需要注意的是尺寸/ precision--一些SQL类型(例如: VARCHAR )有尺寸限制,而.NET类型(如字符串)没有。所以能够知道最有可能的.NET类型是不​​是真的够了...如果你用这,例如,驱动器验证规则,还需要能够防止用户输入无效(例如过大)通过了解更多有关参数,如精度值。需要注意的是,如果你看的SqlClient源里面,他们用特殊的代码来处理类似案件从相应的SQL精度设置小数类型的精度。



请注意,如果唯一的原因,你所需要的.NET类型是能够充填数据到存储过程的参数,你可能想尝试用简单的ToString()在您所有的.NET值,馅串入的SqlParameter的Value属性,并查看是否框架将进行转换/解析为您服务。例如,XML或日期参数,你也许能逃脱发送一个字符串代替。



此外,而不是使用反射来找到每种类型的一个Parse()方法,因为有一个类型的已知的(小)中,则可以得到更好的绩效使用强类型解析代码为每个,如下面的代码。 (请注意,几种类型(如SqlDbType.Udt)不一定有明显的语法分析器method--你需要弄清楚要如何处理这些。)

 公共静态字典< SqlDbType,Func键<字符串对象>> TypeMapper =新词典< SqlDbType,Func键<字符串对象>> 
{
{SqlDbType.BigInt,S = GT; Int64.Parse(S)},
{SqlDbType.Binary,S = GT;空} // TODO:什么解析器?
{SqlDbType.Bit,S = GT; Boolean.Parse(S)},
{SqlDbType.Char,S = GT;小号}
{SqlDbType.Date,S = GT; DateTime.Parse(S)},
{SqlDbType.DateTime,S = GT; DateTime.Parse(S)},
{SqlDbType.DateTime2,S = GT; DateTime.Parse(S)},
{SqlDbType.DateTimeOffset,S = GT; DateTimeOffset.Parse(S)},
{SqlDbType.Decimal,S = GT; Decimal.Parse(S)},
{SqlDbType.Float,S = GT; Double.Parse(S)},
{SqlDbType.Int,S = GT; Int32.Parse(S)},
{SqlDbType.Money,S = GT; Decimal.Parse(S)},
{SqlDbType.NChar,S = GT;小号}
{SqlDbType.NText,S = GT;小号}
{SqlDbType.NVarChar,S = GT;小号}
{SqlDbType.Real,S = GT; Single.Parse(S)},
{SqlDbType.SmallInt,S = GT; Int16.Parse(S)},
{SqlDbType.SmallMoney,S = GT; Decimal.Parse(S)},
{SqlDbType.Structured,S = GT;空} // TODO:什么解析器?
{SqlDbType.Text,S = GT;小号}
{SqlDbType.Time,S = GT; TimeSpan.Parse(S)},
{SqlDbType.Timestamp,S = GT;空} // TODO:什么解析器?
{SqlDbType.TinyInt,S = GT; Byte.Parse(S)},
{SqlDbType.Udt,S = GT;空} //考虑异常,而不是
{SqlDbType.UniqueIdentifier,S = GT;新的GUID(S)},
{SqlDbType.VarBinary,S = GT;空} // TODO:什么解析器?
{SqlDbType.VarChar,S = GT;小号}
{SqlDbType.Variant,S = GT;空} // TODO:什么解析器?
{SqlDbType.Xml,S = GT;小号}
};



以上使用的代码是很容易的,例如



 字符串valueToSet =1234; 
的SqlParameter P =新的SqlParameter();
p.SqlDbType = System.Data.SqlDbType.Int;
p.Value = TypeMapper [p.SqlDbType](valueToSet);


I'm creating 'generic' wrapper above SQL procedures, and I can resolve all required parameters' names and sqltypes, but is there any way how to get it's 'underlying' .NET type?

My goal is to do something like:

SqlParameter param;
object value;
object correctParam = param.GetNETType().GetMethod("Parse", 
    new Type[] { typeof(string) }).Invoke(value.ToString());
param.Value = correctParam;

Where GetNETType is the thing I need. I know that it can be written as switch inside of param.SqlDbType, but this is shorter way, and shorter commented code means lower mainteance :)

解决方案

Unfortunately, as far as I know this mapping is not exposed in code inside the .NET Framework. I've looked through the .NET Framework reference source before for this, and found that inside the .NET code there's a lot of long per-type switch statements, just like the ones you're trying to avoid, but none of them seem to be exposed externally.

If you really just want to map from SqlTypes to the most likley .NET type, I think your best bet is to simply turn the mapping table in the MSDN docs into code. Note that the table on MSDN has (at least) two errors: #1: there is no .NET type called "DateTime2" (I used DateTime) and there is also no type called "Xml" (I used SqlXml).

Anyway, here's the mapping I've been using-- using a Dictionary instead of a switch for ease of access without a separate method.

public static Dictionary<SqlDbType, Type> TypeMap = new Dictionary<SqlDbType, Type>
{
    { SqlDbType.BigInt, typeof(Int64) },
    { SqlDbType.Binary, typeof(Byte[]) },
    { SqlDbType.Bit, typeof(Boolean) },
    { SqlDbType.Char, typeof(String) },
    { SqlDbType.Date, typeof(DateTime) },
    { SqlDbType.DateTime, typeof(DateTime) },
    { SqlDbType.DateTime2, typeof(DateTime) },
    { SqlDbType.DateTimeOffset, typeof(DateTimeOffset) },
    { SqlDbType.Decimal, typeof(Decimal) },
    { SqlDbType.Float, typeof(Double) },
    { SqlDbType.Int, typeof(Int32) },
    { SqlDbType.Money, typeof(Decimal) },
    { SqlDbType.NChar, typeof(String) },
    { SqlDbType.NText, typeof(String) },
    { SqlDbType.NVarChar, typeof(String) },
    { SqlDbType.Real, typeof(Single) },
    { SqlDbType.SmallInt, typeof(Int16) },
    { SqlDbType.SmallMoney, typeof(Decimal) },
    { SqlDbType.Structured, typeof(Object) }, // might not be best mapping...
    { SqlDbType.Text, typeof(String) },
    { SqlDbType.Time, typeof(TimeSpan) },
    { SqlDbType.Timestamp, typeof(Byte[]) },
    { SqlDbType.TinyInt, typeof(Byte) },
    { SqlDbType.Udt, typeof(Object) },  // might not be best mapping...
    { SqlDbType.UniqueIdentifier, typeof(Guid) },
    { SqlDbType.VarBinary, typeof(Byte[]) },
    { SqlDbType.VarChar, typeof(String) },
    { SqlDbType.Variant, typeof(Object) },
    { SqlDbType.Xml, typeof(SqlXml) }, 
};

Note that one thing you'll need to watch out for is size/precision-- some SQL types (e.g. varchar) have size limits, while .NET types (e.g. string) don't. So being able to know the most-likely .NET type is not really enough... if you're using this to, for example, drive validation rules, you also need to be able to prevent users from entering invalid (e.g. too large) values by knowing more about the parameter, like the precision. Note that, if you look inside the SqlClient source, they use special code to handle cases like setting the precision of a Decimal type from the corresponding SQL precision.

Note that if the only reason you need the .NET type is to be able to stuff data into a stored proc parameter, you might want to try simply using ToString() on all your .NET values, stuffing a string into the Value property of the SqlParameter, and seeing if the framework will do the conversion/parsing for you. For example, for an XML or Date parameter you might be able to get away with sending a string instead.

Also, instead of using reflection to find a Parse() method on each type, since there's a known (and small) list of types, you can get better performance by using strongly-typed parsing code for each, like the code below. (Note that several types (e.g. SqlDbType.Udt) don't necessarily have an obvious parser method-- you'll need to figure out how you want to handle those.)

public static Dictionary<SqlDbType, Func<string, object>>  TypeMapper = new Dictionary<SqlDbType, Func<string, object>>
{
    { SqlDbType.BigInt, s => Int64.Parse(s)},
    { SqlDbType.Binary, s => null },  // TODO: what parser?
    { SqlDbType.Bit, s => Boolean.Parse(s) },
    { SqlDbType.Char, s => s },
    { SqlDbType.Date, s => DateTime.Parse(s) },
    { SqlDbType.DateTime, s => DateTime.Parse(s) },
    { SqlDbType.DateTime2, s => DateTime.Parse(s) },
    { SqlDbType.DateTimeOffset, s => DateTimeOffset.Parse(s) },
    { SqlDbType.Decimal, s => Decimal.Parse(s) },
    { SqlDbType.Float, s => Double.Parse(s) },
    { SqlDbType.Int, s => Int32.Parse(s) },
    { SqlDbType.Money, s => Decimal.Parse(s) },
    { SqlDbType.NChar, s => s },
    { SqlDbType.NText, s => s },
    { SqlDbType.NVarChar, s => s },
    { SqlDbType.Real, s => Single.Parse(s) },
    { SqlDbType.SmallInt, s => Int16.Parse(s) },
    { SqlDbType.SmallMoney, s => Decimal.Parse(s) },
    { SqlDbType.Structured, s => null }, // TODO: what parser?
    { SqlDbType.Text, s => s },
    { SqlDbType.Time, s => TimeSpan.Parse(s) },
    { SqlDbType.Timestamp, s => null },  // TODO: what parser?
    { SqlDbType.TinyInt, s => Byte.Parse(s) },
    { SqlDbType.Udt, s => null },  // consider exception instead
    { SqlDbType.UniqueIdentifier, s => new Guid(s) },
    { SqlDbType.VarBinary, s => null },  // TODO: what parser?
    { SqlDbType.VarChar, s => s },
    { SqlDbType.Variant, s => null }, // TODO: what parser?
    { SqlDbType.Xml, s => s }, 
};

The code to use above is pretty easy, e.g. :

        string valueToSet = "1234";
        SqlParameter p = new SqlParameter();
        p.SqlDbType = System.Data.SqlDbType.Int;
        p.Value = TypeMapper[p.SqlDbType](valueToSet);

这篇关于如何检索给定的StoredProcedure在SQL参数.NET类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆