簡體   English   中英

.NET系統類型為SqlDbType

[英].NET System Type to 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)];
     }

有人知道如何以更清潔,更好,更好的方式獲得相同的結果嗎?

你的方法是一個良好的開端,但填充該字典應該只進行一次 ,正如伊恩在評論中所說。

這里有一個GIST基於相同的想法,雖然它不會在相同的類型集之間進行轉換: https//gist.github.com/abrahamjp/858392

警告

我在下面有一個工作示例 ,但您需要注意這種方法確實存在一些問題。 例如:

  • 對於一個string ,你如何在CharNCharVarCharNVarCharTextNText (或者甚至是Xml之間選擇正確的string
  • 對於像byte[]這樣的blob,你應該使用BinaryVarBinary還是Image
  • 對於decimalfloatdouble ,你應該選擇DecimalFloatMoneySmallMoney還是Real
  • 對於DateTime ,您需要DateTime2DateTimeOffsetDateTime還是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);

看來這種查找表已經可用,雖然不在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類型,所以我使用反射來獲取它。 太糟糕了SqlDbType沒有一些接口可以保存這個.Value屬性,並且不需要反射。
它並不完美,但您不必手動創建,維護或填充字典。 您可以在現有的dict中查找類型,如果它不存在,請使用upper方法自動添加映射。 幾乎是自動生成的。
還要處理SQL Server將來可能會收到的任何新類型。

我的辦公室伙伴給了我一個嘗試SqlParameter屬性的想法:

Func<Object, SqlDbType> getSqlType = val => new SqlParameter("Test", val).SqlDbType;
Func<Type, SqlDbType> getSqlType2 = type => new SqlParameter("Test", type.IsValueType?Activator.CreateInstance(type):null).SqlDbType;

//returns nvarchar...
Object obj = "valueToTest";
getSqlType(obj).Dump();
getSqlType2(typeof(String)).Dump();

//returns int...
obj = 4;
getSqlType(obj).Dump();
getSqlType2(typeof(Int32)).Dump();

//returns bigint...
obj = Int64.MaxValue;
getSqlType(obj).Dump();
getSqlType2(typeof(Int64)).Dump();

https://dotnetfiddle.net/8heM4H

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM