.NET系统类型为SqlDbType
我正在寻找.Net System.Type和SqlDbType之间的智能转换。 我发现它是以下想法:
private static SqlDbType TypeToSqlDbType(Type t) { String name = t.Name; SqlDbType val = SqlDbType.VarChar; // default value try { if (name.Contains("16") || name.Contains("32") || name.Contains("64")) { name = name.Substring(0, name.Length - 2); } val = (SqlDbType)Enum.Parse(typeof(SqlDbType), name, true); } catch (Exception) { // add error handling to suit your taste } return val; }
上面的代码不是很好,是一个代码气味,这就是为什么我写了以下,天真,不聪明,但有用的function,基于https://msdn.microsoft.com/en-us/library/cc716729( v = vs.110).aspx :
public static SqlDbType ConvertiTipo(Type giveType) { var typeMap = new Dictionary(); typeMap[typeof(string)] = SqlDbType.NVarChar; typeMap[typeof(char[])] = SqlDbType.NVarChar; typeMap[typeof(int)] = SqlDbType.Int; typeMap[typeof(Int32)] = SqlDbType.Int; typeMap[typeof(Int16)] = SqlDbType.SmallInt; typeMap[typeof(Int64)] = SqlDbType.BigInt; typeMap[typeof(Byte[])] = SqlDbType.VarBinary; typeMap[typeof(Boolean)] = SqlDbType.Bit; typeMap[typeof(DateTime)] = SqlDbType.DateTime2; typeMap[typeof(DateTimeOffset)] = SqlDbType.DateTimeOffset; typeMap[typeof(Decimal)] = SqlDbType.Decimal; typeMap[typeof(Double)] = SqlDbType.Float; typeMap[typeof(Decimal)] = SqlDbType.Money; typeMap[typeof(Byte)] = SqlDbType.TinyInt; typeMap[typeof(TimeSpan)] = SqlDbType.Time; return typeMap[(giveType)]; }
有人知道如何以更清洁,更好,更好的方式获得相同的结果吗?
你的方法是一个良好的开端,但填充该字典应该只进行一次 ,正如伊恩在评论中所说。
这里有一个GIST基于相同的想法,虽然它不会在相同的类型集之间进行转换: https : //gist.github.com/abrahamjp/858392
警告
我在下面有一个工作示例 ,但您需要注意这种方法确实存在一些问题。 例如:
- 对于一个
string
,你如何在Char
,NChar
,VarChar
,NVarChar
,Text
或NText
(或者甚至是Xml
)之间选择正确的string
? - 对于像
byte[]
这样的blob,你应该使用Binary
,VarBinary
还是Image
? - 对于
decimal
,float
和double
,你应该选择Decimal
,Float
,Money
,SmallMoney
还是Real
? - 对于
DateTime
,您需要DateTime2
,DateTimeOffset
,DateTime
还是SmallDateTime
? - 你在使用
Nullable
类型,比如int?
? 那些应该最有可能提供与底层类型相同的SqlDbType
。
另外,只提供一个Type
不会告诉你任何其他约束,比如字段大小和精度。 做出正确的决定还涉及如何在应用程序中使用数据以及如何将数据存储在数据库中。
最好的办法是让ORM为你做这件事。
码
public static class SqlHelper { private static Dictionary typeMap; // Create and populate the dictionary in the static constructor static SqlHelper() { typeMap = new Dictionary(); typeMap[typeof(string)] = SqlDbType.NVarChar; typeMap[typeof(char[])] = SqlDbType.NVarChar; typeMap[typeof(byte)] = SqlDbType.TinyInt; typeMap[typeof(short)] = SqlDbType.SmallInt; typeMap[typeof(int)] = SqlDbType.Int; typeMap[typeof(long)] = SqlDbType.BigInt; typeMap[typeof(byte[])] = SqlDbType.Image; typeMap[typeof(bool)] = SqlDbType.Bit; typeMap[typeof(DateTime)] = SqlDbType.DateTime2; typeMap[typeof(DateTimeOffset)] = SqlDbType.DateTimeOffset; typeMap[typeof(decimal)] = SqlDbType.Money; typeMap[typeof(float)] = SqlDbType.Real; typeMap[typeof(double)] = SqlDbType.Float; typeMap[typeof(TimeSpan)] = SqlDbType.Time; /* ... and so on ... */ } // Non-generic argument-based method public static SqlDbType GetDbType(Type giveType) { // Allow nullable types to be handled giveType = Nullable.GetUnderlyingType(giveType) ?? giveType; if (typeMap.ContainsKey(giveType)) { return typeMap[giveType]; } throw new ArgumentException($"{giveType.FullName} is not a supported .NET class"); } // Generic version public static SqlDbType GetDbType() { return GetDbType(typeof(T)); } }
这就是你如何使用它:
var sqlDbType = SqlHelper.GetDbType(); // or: var sqlDbType = SqlHelper.GetDbType(typeof(DateTime?)); // or: var sqlDbType = SqlHelper.GetDbType(property.PropertyType);
看来这种查找表已经可用,虽然不在System.Data
(或.Object
或.Type
)中,而是在System.Web中。
项目 – >添加参考 – > System.Web – >确定
然后https://msdn.microsoft.com/en-us/library/system.data.sqldbtype(v=vs.110).aspx也说
设置命令参数时,链接SqlDbType和DbType。 因此,设置DbType会将SqlDbType更改为支持的SqlDbType。
所以,理论上这应该工作;)
using Microsoft.SqlServer.Server; // SqlDataRecord and SqlMetaData using System; using System.Collections; // IEnumerator and IEnumerable using System.Collections.Generic; // general IEnumerable and IEnumerator using System.Data; // DataTable and SqlDataType using System.Data.SqlClient; // SqlConnection, SqlCommand, and SqlParameter using System.Web.UI.WebControls; // for Parameters.Convert... functions private static SqlDbType TypeToSqlDbType(Type t) { DbType dbtc = Parameters.ConvertTypeCodeToDbType(t.GetTypeCodeImpl()); SqlParameter sp = new SqlParameter(); // DbParameter dp = new DbParameter(); // dp.DbType = dbtc; sp.DbType = dbtc; return sp.SqlDbType; }
编辑:我在想,这适用于System.Data.SqlTypes类型。 我会留在这里以防万一将来帮助某人。
我做这样的事情:
object objDbValue = DbReader.GetValue(columnIndex); Type sqlType = DbReader.GetFieldType(columnIndex); Type clrType = null; if (sqlType.Name.StartsWith("Sql")) { var objClrValue = objDbValue.GetType() .GetProperty("Value") .GetValue(objDbValue, null); clrType = objClrValue.GetType(); }
因为每个SqlDbType都有一个.Value属性,它是实际的底层CLR类型,所以我使用reflection来获取它。 太糟糕了SqlDbType没有一些接口可以保存这个.Value属性并且不需要reflection。
它并不完美,但您不必手动创建,维护或填充字典。 您可以在现有dict中查找类型,如果它不存在,请使用upper方法自动添加映射。 几乎是自动生成的。
还要处理SQL Server将来可能会收到的任何新类型。