.NET System Type to SqlDbType

Your approach is a good start, but populating that dictionary should only be done once, as Ian says in a comment.

There is a GIST here that is based on the same idea, although it doesn't convert between the same sets of types: https://gist.github.com/abrahamjp/858392

Caveat

I have a working example below, but you need to be aware that this approach does have a few problems. For example:

  • For a string, how do you pick the correct one between Char, NChar, VarChar, NVarChar, Text or NText (or even Xml, maybe)?
  • And for blobs like byte[], should you use Binary, VarBinary or Image?
  • For decimal, float and double, should you go for Decimal, Float, Money, SmallMoney or Real?
  • For a DateTime, do you need DateTime2, DateTimeOffset, DateTime, or SmallDateTime?
  • Are you using Nullable types, like int?? Those should most likely give the same SqlDbType as the underlying type.

Also, just providing a Type tells you nothing of other constraints, like field size and precision. Making the right decision is also about how the data is used in your application and how it is stored in the database.

The best thing to do is really to let an ORM do this for you.

Code

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

And this is how you would use it:

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

It appears that this sort of lookup table is already available, albeit not in System.Data (or .Object or .Type) but rather in System.Web.

Project -> Add Reference -> System.Web -> OK

Then https://msdn.microsoft.com/en-us/library/system.data.sqldbtype(v=vs.110).aspx also says

When setting command parameters, the SqlDbType and DbType are linked. Therefore, setting the DbType changes the SqlDbType to a supporting SqlDbType.

So, this should theoretically work;)

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