私は、.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;
}
上記のコードはあまり良くなく、コードの臭いがします。そのため、私は次のような素朴でスマートではないが便利な関数を記述しました。https://msdn.microsoft.com/en-us/library/cc716729(v=vs.110).aspx:
public static SqlDbType ConvertiTipo(Type giveType)
{
var typeMap = new Dictionary<Type, SqlDbType>();
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)];
}
同じ結果をよりきれいに、より良く、そして素敵な方法で得る方法を誰か知っていますか?
ベストアンサー1
あなたのアプローチは良いスタートですが、辞書にデータを入力するのは一度イアンがコメントで言っているように。
同じアイデアに基づいた GIST がここにありますが、同じ型セット間で変換は行われません。https://gist.github.com/abrahamjp/858392
警告
私は持っている実例以下に説明しますが、このアプローチにはいくつかの問題があることに注意する必要があります。たとえば、
- の場合、、、、、の中
string
から正しいものをどのように選びますか?Char
NChar
VarChar
NVarChar
Text
NText
(あるいはXml
、もしかしたら)? - のような BLOB の場合、との
byte[]
どちらを使用すればよいのでしょうか。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<Type, SqlDbType> typeMap;
// Create and populate the dictionary in the static constructor
static SqlHelper()
{
typeMap = new Dictionary<Type, SqlDbType>();
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<T>()
{
return GetDbType(typeof(T));
}
}
使い方は次のようになります:
var sqlDbType = SqlHelper.GetDbType<string>();
// or:
var sqlDbType = SqlHelper.GetDbType(typeof(DateTime?));
// or:
var sqlDbType = SqlHelper.GetDbType(property.PropertyType);