Я сажусь писать массивный оператор switch(), чтобы преобразовать типы данных SQL в типы данных CLR, чтобы генерировать классы из хранимых процедур MSSQL. Я использую эту диаграмму в качестве справки. Прежде чем я зайду слишком далеко в то, что, вероятно, займет весь день и будет огромной болью для полного тестирования, я хотел бы обратиться к сообществу SO, чтобы узнать, не написал ли кто-нибудь еще или нашел что-то на C # для выполнения этого, казалось бы, распространенного и, конечно, утомительное занятие.
У кого-нибудь есть функция С#, которая сопоставляет тип данных SQL столбца с его эквивалентом CLR?
Ответы (12)
Это тот, который мы используем. Вы можете настроить его (например, обнуляемые/необнуляемые типы и т. д.), но это должно сэкономить вам большую часть ввода.
public static Type GetClrType(SqlDbType sqlType)
{
switch (sqlType)
{
case SqlDbType.BigInt:
return typeof(long?);
case SqlDbType.Binary:
case SqlDbType.Image:
case SqlDbType.Timestamp:
case SqlDbType.VarBinary:
return typeof(byte[]);
case SqlDbType.Bit:
return typeof(bool?);
case SqlDbType.Char:
case SqlDbType.NChar:
case SqlDbType.NText:
case SqlDbType.NVarChar:
case SqlDbType.Text:
case SqlDbType.VarChar:
case SqlDbType.Xml:
return typeof(string);
case SqlDbType.DateTime:
case SqlDbType.SmallDateTime:
case SqlDbType.Date:
case SqlDbType.Time:
case SqlDbType.DateTime2:
return typeof(DateTime?);
case SqlDbType.Decimal:
case SqlDbType.Money:
case SqlDbType.SmallMoney:
return typeof(decimal?);
case SqlDbType.Float:
return typeof(double?);
case SqlDbType.Int:
return typeof(int?);
case SqlDbType.Real:
return typeof(float?);
case SqlDbType.UniqueIdentifier:
return typeof(Guid?);
case SqlDbType.SmallInt:
return typeof(short?);
case SqlDbType.TinyInt:
return typeof(byte?);
case SqlDbType.Variant:
case SqlDbType.Udt:
return typeof(object);
case SqlDbType.Structured:
return typeof(DataTable);
case SqlDbType.DateTimeOffset:
return typeof(DateTimeOffset?);
default:
throw new ArgumentOutOfRangeException("sqlType");
}
}
Вот версия, которая принимает значение nullable.
public static Type GetClrType(SqlDbType sqlType, bool isNullable)
{
switch (sqlType)
{
case SqlDbType.BigInt:
return isNullable ? typeof(long?) : typeof(long);
case SqlDbType.Binary:
case SqlDbType.Image:
case SqlDbType.Timestamp:
case SqlDbType.VarBinary:
return typeof(byte[]);
case SqlDbType.Bit:
return isNullable ? typeof(bool?) : typeof(bool);
case SqlDbType.Char:
case SqlDbType.NChar:
case SqlDbType.NText:
case SqlDbType.NVarChar:
case SqlDbType.Text:
case SqlDbType.VarChar:
case SqlDbType.Xml:
return typeof(string);
case SqlDbType.DateTime:
case SqlDbType.SmallDateTime:
case SqlDbType.Date:
case SqlDbType.Time:
case SqlDbType.DateTime2:
return isNullable ? typeof(DateTime?) : typeof(DateTime);
case SqlDbType.Decimal:
case SqlDbType.Money:
case SqlDbType.SmallMoney:
return isNullable ? typeof(decimal?) : typeof(decimal);
case SqlDbType.Float:
return isNullable ? typeof(double?) : typeof(double);
case SqlDbType.Int:
return isNullable ? typeof(int?) : typeof(int);
case SqlDbType.Real:
return isNullable ? typeof(float?) : typeof(float);
case SqlDbType.UniqueIdentifier:
return isNullable ? typeof(Guid?) : typeof(Guid);
case SqlDbType.SmallInt:
return isNullable ? typeof(short?) : typeof(short);
case SqlDbType.TinyInt:
return isNullable ? typeof(byte?) : typeof(byte);
case SqlDbType.Variant:
case SqlDbType.Udt:
return typeof(object);
case SqlDbType.Structured:
return typeof(DataTable);
case SqlDbType.DateTimeOffset:
return isNullable ? typeof(DateTimeOffset?) : typeof(DateTimeOffset);
default:
throw new ArgumentOutOfRangeException("sqlType");
}
}
Вам не нужна функция. Я думаю, вы ищете
dt.Columns[i].DataType.UnderlyingSystemType
dt — таблица данных
Это вернет тип CLR для соответствующего столбца. Надеюсь, это поможет, и, кстати, это мой первый ответ на переполнение стека
Это не дает прямого ответа на заданный вопрос, но отвечает на общий связанный вопрос. Получив IDataReader
, вы можете вызвать IDataRecord.GetFieldType(int)
чтобы «[получить] информацию Type
, соответствующую типу Object
, которая будет возвращена из GetValue
».
Я включаю это расширение (вы можете легко заменить строковый ключ в словаре на SqlDbType, как это реализовал Грег, или даже поддерживать оба) в мою модель и предоставить свойство, которое преобразует тип CLR:
namespace X.Domain.Model
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
public class StoredProcedureParameter : DomainObject
{
public StoredProcedureParameter() { }
public string StoredProcedure { get; set; }
public string ProcedureSchema { get; set; }
public string ProcedureName { get; set; }
public string ParameterName { get; set; }
public string ParameterOrder { get; set; }
public string ParameterMode { get; set; }
public string SqlDataType { get; set; }
public Type DataType { get { return this.SqlDataType.ToClrType(); } }
}
static class StoredProcedureParameterExtensions
{
private static Dictionary<string, Type> Mappings;
public static StoredProcedureParameterExtensions()
{
Mappings = new Dictionary<string, Type>();
Mappings.Add("bigint", typeof(Int64));
Mappings.Add("binary", typeof(Byte[]));
Mappings.Add("bit", typeof(Boolean));
Mappings.Add("char", typeof(String));
Mappings.Add("date", typeof(DateTime));
Mappings.Add("datetime", typeof(DateTime));
Mappings.Add("datetime2", typeof(DateTime));
Mappings.Add("datetimeoffset", typeof(DateTimeOffset));
Mappings.Add("decimal", typeof(Decimal));
Mappings.Add("float", typeof(Double));
Mappings.Add("image", typeof(Byte[]));
Mappings.Add("int", typeof(Int32));
Mappings.Add("money", typeof(Decimal));
Mappings.Add("nchar", typeof(String));
Mappings.Add("ntext", typeof(String));
Mappings.Add("numeric", typeof(Decimal));
Mappings.Add("nvarchar", typeof(String));
Mappings.Add("real", typeof(Single));
Mappings.Add("rowversion", typeof(Byte[]));
Mappings.Add("smalldatetime", typeof(DateTime));
Mappings.Add("smallint", typeof(Int16));
Mappings.Add("smallmoney", typeof(Decimal));
Mappings.Add("text", typeof(String));
Mappings.Add("time", typeof(TimeSpan));
Mappings.Add("timestamp", typeof(Byte[]));
Mappings.Add("tinyint", typeof(Byte));
Mappings.Add("uniqueidentifier", typeof(Guid));
Mappings.Add("varbinary", typeof(Byte[]));
Mappings.Add("varchar", typeof(String));
}
public static Type ToClrType(this string sqlType)
{
Type datatype = null;
if (Mappings.TryGetValue(sqlType, out datatype))
return datatype;
throw new TypeLoadException(string.Format("Can not load CLR Type from {0}", sqlType));
}
}
}
Вы можете попробовать Wizardby. Однако он сопоставляет так называемые «собственные» типы данных с DbType
, которые затем легко преобразовать в типы CLR. Если это подходит, вам понадобится соответствующий IDbTypeMapper
— либо SqlServer2000TypeMapper
, либо SqlServer2005TypeMapper
.
Я думаю, что для этого нет встроенных функций, но вы можете использовать VS для создания классов для своих таблиц, а затем попытаться их отредактировать.
Почему бы не создать типизированный набор данных, а дизайнер VS сделает сопоставление за вас? Если проект не должен адаптироваться во время выполнения к различным схемам, вам следует использовать методы генерации кода для создания своих классов, будь то встроенные конструкторы (т. е. типизированные наборы данных) или пользовательские (схема->XML->XSLT->. cs).
Обычно я просто использую свойство Value для преобразования SqlType в собственный тип .NET. Это делает работу большую часть времени. Если у меня есть угловой случай, я просто напишу быструю вспомогательную функцию.
int i = dataReader.GetSqlInt32(0).Value;
Я понимаю, что вы обсуждаете написание оператора switch, но вот альтернатива для Sql Server (аналогичные концепции работают для других БД)
Рассмотрите возможность использования SysObjects для получения полных типов данных и создания вашего класса:
declare @ProcName varchar(255)
select @ProcName='Table, View, or Proc'
SELECT --DISTINCT
b.name
, c.name Type
, b.xtype
, b.length
, b.isoutparam
FROM
sysObjects a
INNER JOIN sysCOLUMNs b ON a.id=b.id
INNER JOIN systypes c ON b.xtype=c.xtype
WHERE
a.name=@ProcName
order by b.colorder
Теперь вы просто перечисляете DataTable вместо более длинного оператора.
Dictionary.TryGetValue()
этот подход, показанный здесь, быстрее или медленнее, чем switch...case
подход, показанный в другом месте этой темы?
- person Dib; 23.10.2015
try { return Convert.ChangeType(value_to_convert, Parameter.ConvertDbTypeToTypeCode(SqlMetaData_instance.DbType); }
также доступно: ConvertTypeCodeToDbType (msdn.microsoft.com/en-us/library/) - person mpag   schedule 12.12.2017