.NET システム型から SqlDbType への質問

.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;
    }

上記のコードはあまり良くなく、コードの臭いがします。そのため、私は次のような素朴でスマートではないが便利な関数を記述しました。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から正しいものをどのように選びますか?CharNCharVarCharNVarCharTextNText (あるいはXml、もしかしたら)?
  • のような BLOB の場合、とのbyte[]どちらを使用すればよいのでしょうか。BinaryVarBinaryImage
  • decimalfloat、については、 、、、doubleのどれを選ぶべきでしょうか?DecimalFloatMoneySmallMoneyReal
  • の場合、、、、または のどれDateTimeが必要ですか?DateTime2DateTimeOffsetDateTimeSmallDateTime
  • 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);

おすすめ記事