.NET系统类型为SqlDbType

Sim*_*lvo 14 c# ado.net system.data

我正在寻找.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;
    }
Run Code Online (Sandbox Code Playgroud)

上面的代码不是很好,是一个代码气味,这就是为什么我写了以下,天真,不聪明,但有用的功能,基于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)];
     }
Run Code Online (Sandbox Code Playgroud)

有人知道如何以更清洁,更好,更好的方式获得相同的结果吗?

And*_*lad 17

你的方法是一个良好的开端,但填充该字典应该只进行一次,正如伊恩在评论中所说.

这里有一个GIST基于相同的想法,虽然它不会在相同的类型集之间进行转换:https://gist.github.com/abrahamjp/858392

警告

我在下面有一个工作示例,但您需要注意这种方法确实存在一些问题.例如:

  • 对于string,你如何挑选之间正确的Char,NChar,VarChar,NVarChar,TextNText (甚至Xml,也许)
  • 对于blob来说byte[],你应该使用Binary,VarBinary还是Image
  • 对于decimal,floatdouble,你应该去Decimal,Float,Money,SmallMoneyReal
  • 对于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));
    }
}
Run Code Online (Sandbox Code Playgroud)

这就是你如何使用它:

var sqlDbType = SqlHelper.GetDbType<string>();
// or:
var sqlDbType = SqlHelper.GetDbType(typeof(DateTime?));
// or:
var sqlDbType = SqlHelper.GetDbType(property.PropertyType);
Run Code Online (Sandbox Code Playgroud)


mpa*_*pag 10

看起来这种查找表已经可用,尽管不在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;
}
Run Code Online (Sandbox Code Playgroud)