2016-03-02 8 views
8

.Net System.TypeとSqlDbTypeの間のスマートな変換を探していました。それは、次のアイデアだった私が見つかりました.NET System Type to 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)]; 
    } 

誰かが同じ結果をよりきれいでいい方法で得る方法を知っていますか?

+2

はOKです。一生のうちに*回*する。 :)(変更はありません) – Ian

+0

私の答えがあなたを助けたら、あなたの選択した答えとしてそれをマークしてください。 :) –

答えて

13

あなたのアプローチは良いスタートですが、その辞書を設定するのは、と1回だけです。

それは種類の同じセット間で変換しませんが、同じ考え方に基づいており、ここでGISTがあります:https://gist.github.com/abrahamjp/858392

が警告

私は以下のa working exampleを持っていますが、次のものが必要このアプローチにはいくつかの問題があることに注意してください。たとえば:stringについては

  • は、どのように(多分、あるいはXmlCharNCharVarCharNVarCharTextまたはNTextの間に正しいものを選ぶのですか?
  • のようなブロブの場合、Binary,VarBinaryまたはImageを使用しますか? decimalfloatdoubleについては
  • 、あなたはDecimalFloatMoneySmallMoneyまたはRealのために行くべきですか?
  • DateTimeの場合、DateTime2,DateTimeOffset,DateTimeまたはSmallDateTimeが必要ですか?
  • int?のようにNullableタイプを使用していますか?それらはおそらく同じ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); 
+1

いいね!私は辞書に型が存在するかどうか( 'ContainsKey')を確認するためのチェックを追加し、デフォルトの' KeyNotFoundException'ではなく独自の詳細メッセージで 'NotSupportedException'(またはカスタム例外)を投げないようにします。サポートされていないタイプが渡された場合、後でトラブルシューティングが容易になる可能性があります。 – Igor

+1

チップをありがとう。 'NotSupportedException'はこのタイプのものではないので、私は' ArgumentException'をスローする答えを編集しました。 –

0

は編集:私は考えていた、これはSystem.Data.SqlTypesタイプのために動作します。私は、将来誰かを助ける場合に備えて、ここに残しておきます。すべてのは、SqlDbTypeが、私はそれを得るためにリフレクションを使用して、実際の基礎となるCLR型です.Valueの性質を持っているので

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プロパティとリフレクションを保持するインターフェイスがありません。
これは完璧ではありませんが、手動で辞書を作成、管理、移入する必要はありません。既存のdictの型を検索するだけで、存在しない場合はupperメソッドを使用して自動的にマッピングを追加できます。 かなり自動生成されます。
また、SQL Serverが将来受け取る可能性がある新しい種類のものも処理します。

+0

"編集:私が返信したコメントがどこに行きましたか分かりません。"ああ、あなたは正しい、他の方向については、私は事前に人口が多い辞書よりも良い答えを持っていない。通常、ユースケースはsql型からclr型ですが、1つのsql型は複数のclr型にマップできるためです。 –

+0

[SqlDbType](https://msdn.microsoft.com/en-us/library/system.data.sqldbtype(v = vs.110).aspx)のように見えるので列挙型なので、それがどのようにCLRタイプに関する情報また、クエリを作成する場合、クエリの結果を正しいCLRタイプに変換するためにのみ機能します。 – Igor

+0

申し訳ありませんが、私はちょっと考え直したかったのですぐにコメントを削除しました。私の最初のコメントは* "これは反対の方向に向かないのですか?" *。今、私は@Igorにもっと興味があります。希望する 'SqlDbType'は列挙型です。 –

0

このタイプのルックアップテーブルは、System.Data(または.Objectまたは.Type)ではなく、System.Webには存在していますが、既に利用可能です。

プロジェクト - > [参照の追加] - > [System.Webの - コマンドパラメータを設定する場合> OK

はその後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; 
} 
関連する問題