Вопрос по c#, types – Кто-нибудь получил функцию C #, которая отображает тип данных SQL столбца в его CLR-эквивалент?

44

Я сижу, чтобы написать массивный оператор switch (), чтобы превратить типы данных SQL в типы данных CLR, чтобы сгенерировать классы из хранимых процедур MSSQL. Я используюэтот график в качестве ссылки. Прежде чем я углублюсь в то, что, вероятно, займет целый день, и мне будет очень трудно полностью протестировать, я хотел бы обратиться к SO-сообществу, чтобы узнать, написал ли кто-нибудь еще или нашел что-то в C #, чтобы выполнить это, казалось бы, общее и, безусловно, утомительное занятие.

Это для коммерческой разработки. Chris McCall
В прошлом я реализовывал очень похожую систему, но не для C #. Я хотел создать что-то подобное, но я пока не дошел до этого. Ваша реализация будет закрыта или может быть с открытым исходным кодом? Потому что я уверен, что я и другие были бы очень заинтересованы в реализации того, что вы описываете, с открытым исходным кодом. Daniel Pryden
Это может быть недоступно в 2009 году, но System.Web может иметь то, что требуется здесь:stackoverflow.com/a/28561947/4228193 . try { return Convert.ChangeType(value_to_convert, Parameter.ConvertDbTypeToTypeCode(SqlMetaData_instance.DbT‌​ype); } также доступно: ConvertTypeCodeToDbType (msdn.microsoft.com/en-us/library/…) mpag

Ваш Ответ

12   ответов
3

оваре на 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));
            }
        }
    }
68

который мы используем. Вы можете настроить его (например, обнуляемые / ненулевые типы и т. Д.), Но это должно сэкономить вам большую часть набора текста.

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");
    }
}
@ user457104 - Хм ... вы называете это как любой другой метод.
Ах я вижу. Благодарю.
Как вы используете этот метод?
Нет, я имею в виду, я не понимаю, для чего вы его используете. Используете ли вы возвращаемое значение для динамического создания типа? Вы используете это, чтобы сравнить это с чем-то еще? В коде, в какой ситуации я хотел бы преобразовать из SqlDbType в тип? Я уверен, что это хорошее применение, но я не могу думать об этом. Следовательно, я спрашиваю.
@ user457104 - Мы используем его в нашем инструменте, который генерирует классы-оболочки .NET для наших хранимых процедур. Он определяет типы параметров SQL и генерирует оболочку с соответствующим типом CLR, используя эту функцию. На самом деле это не очень распространенный случай использования.
8
    /****** Object:  Table [dbo].[DbVsCSharpTypes]    Script Date: 03/20/2010 03:07:56 ******/
    IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[DbVsCSharpTypes]') 
    AND type in (N'U'))
    DROP TABLE [dbo].[DbVsCSharpTypes]
    GO

    /****** Object:  Table [dbo].[DbVsCSharpTypes]    Script Date: 03/20/2010 03:07:56 ******/
    SET ANSI_NULLS ON
    GO

    SET QUOTED_IDENTIFIER ON
    GO

    CREATE TABLE [dbo].[DbVsCSharpTypes](
        [DbVsCSharpTypesId] [int] IDENTITY(1,1) NOT NULL,
        [Sql2008DataType] [varchar](200) NULL,
        [CSharpDataType] [varchar](200) NULL,
        [CLRDataType] [varchar](200) NULL,
        [CLRDataTypeSqlServer] [varchar](2000) NULL,

     CONSTRAINT [PK_DbVsCSharpTypes] PRIMARY KEY CLUSTERED 
    (
        [DbVsCSharpTypesId] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    ) ON [PRIMARY]

    GO


    SET NOCOUNT ON;
    SET XACT_ABORT ON;
    GO

    SET IDENTITY_INSERT [dbo].[DbVsCSharpTypes] ON;
    BEGIN TRANSACTION;
    INSERT INTO [dbo].[DbVsCSharpTypes]([DbVsCSharpTypesId], [Sql2008DataType], [CSharpDataType], [CLRDataType], [CLRDataTypeSqlServer])
    SELECT 1, N'bigint', N'long', N'Int64, Nullable<Int64>', N'SqlInt64' UNION ALL
    SELECT 2, N'binary', N'byte[]', N'Byte[]', N'SqlBytes, SqlBinary' UNION ALL
    SELECT 3, N'bit', N'bool', N'Boolean, Nullable<Boolean>', N'SqlBoolean' UNION ALL
    SELECT 4, N'char', N'char', NULL, NULL UNION ALL
    SELECT 5, N'cursor', NULL, NULL, NULL UNION ALL
    SELECT 6, N'date', N'DateTime', N'DateTime, Nullable<DateTime>', N'SqlDateTime' UNION ALL
    SELECT 7, N'datetime', N'DateTime', N'DateTime, Nullable<DateTime>', N'SqlDateTime' UNION ALL
    SELECT 8, N'datetime2', N'DateTime', N'DateTime, Nullable<DateTime>', N'SqlDateTime' UNION ALL
    SELECT 9, N'DATETIMEOFFSET', N'DateTimeOffset', N'DateTimeOffset', N'DateTimeOffset, Nullable<DateTimeOffset>' UNION ALL
    SELECT 10, N'decimal', N'decimal', N'Decimal, Nullable<Decimal>', N'SqlDecimal' UNION ALL
    SELECT 11, N'float', N'double', N'Double, Nullable<Double>', N'SqlDouble' UNION ALL
    SELECT 12, N'geography', NULL, NULL, N'SqlGeography is defined in Microsoft.SqlServer.Types.dll, which is installed with SQL Server and can be downloaded from the SQL Server 2008 feature pack.' UNION ALL
    SELECT 13, N'geometry', NULL, NULL, N'SqlGeometry is defined in Microsoft.SqlServer.Types.dll, which is installed with SQL Server and can be downloaded from the SQL Server 2008 feature pack.' UNION ALL
    SELECT 14, N'hierarchyid', NULL, NULL, N'SqlHierarchyId is defined in Microsoft.SqlServer.Types.dll, which is installed with SQL Server and can be downloaded from the SQL Server 2008 feature pack.' UNION ALL
    SELECT 15, N'image', NULL, NULL, NULL UNION ALL
    SELECT 16, N'int', N'int', N'Int32, Nullable<Int32>', N'SqlInt32' UNION ALL
    SELECT 17, N'money', N'decimal', N'Decimal, Nullable<Decimal>', N'SqlMoney' UNION ALL
    SELECT 18, N'nchar', N'string', N'String, Char[]', N'SqlChars, SqlString' UNION ALL
    SELECT 19, N'ntext', NULL, NULL, NULL UNION ALL
    SELECT 20, N'numeric', N'decimal', N'Decimal, Nullable<Decimal>', N'SqlDecimal' UNION ALL
    SELECT 21, N'nvarchar', N'string', N'String, Char[]', N'SqlChars, SqlStrinG SQLChars is a better match for data transfer and access, and SQLString is a better match for performing String operations.' UNION ALL
    SELECT 22, N'nvarchar(1), nchar(1)', N'string', N'Char, String, Char[], Nullable<char>', N'SqlChars, SqlString' UNION ALL
    SELECT 23, N'real', N'single', N'Single, Nullable<Single>', N'SqlSingle' UNION ALL
    SELECT 24, N'rowversion', N'byte[]', N'Byte[]', NULL UNION ALL
    SELECT 25, N'smallint', N'smallint', N'Int16, Nullable<Int16>', N'SqlInt16' UNION ALL
    SELECT 26, N'smallmoney', N'decimal', N'Decimal, Nullable<Decimal>', N'SqlMoney' UNION ALL
    SELECT 27, N'sql_variant', N'object', N'Object', NULL UNION ALL
    SELECT 28, N'table', NULL, NULL, NULL UNION ALL
    SELECT 29, N'text', N'string', NULL, NULL UNION ALL
    SELECT 30, N'time', N'TimeSpan', N'TimeSpan, Nullable<TimeSpan>', N'TimeSpan' UNION ALL
    SELECT 31, N'timestamp', NULL, NULL, NULL UNION ALL
    SELECT 32, N'tinyint', N'byte', N'Byte, Nullable<Byte>', N'SqlByte' UNION ALL
    SELECT 33, N'uniqueidentifier', N'Guid', N'Guid, Nullable<Guid>', N'SqlGuidUser-defined type(UDT)The same class that is bound to the user-defined type in the same assembly or a dependent assembly.' UNION ALL
    SELECT 34, N'varbinary ', N'byte[]', N'Byte[]', N'SqlBytes, SqlBinary' UNION ALL
    SELECT 35, N'varbinary(1), binary(1)', N'byte', N'byte, Byte[], Nullable<byte>', N'SqlBytes, SqlBinary' UNION ALL
    SELECT 36, N'varchar', NULL, NULL, NULL UNION ALL
    SELECT 37, N'xml', NULL, NULL, N'SqlXml'
    COMMIT;
    RAISERROR (N'[dbo].[DbVsCSharpTypes]: Insert Batch: 1.....Done!', 10, 1) WITH NOWAIT;
    GO

    SET IDENTITY_INSERT [dbo].[DbVsCSharpTypes] OFF;
Я не могу поверить, что никто не заметил этого за последние 4,5 года, но SQL-код Bigint не эквивалентен C # short. Я думаю, вы имели в виду long (он же Int64)!
Единственный способ обработки данных - это возможность обрабатывать метаданные. Чтобы иметь возможность обрабатывать метаданные, нужно уметь использовать их данные. Чтобы иметь возможность использовать свои данные, они должны быть описаны правильно ...
спасибо, исправлено ... я не кодировал в C # последние 4 года ...
Хорошая точка зрения. Единственная причина, по которой я мог придумать, это просто тот факт, что код находился в состоянии «в процессе разработки». - то есть без тестирования сейчас я изменил его на NOT NULL по интуиции ... если кто-то не объяснит, почему это не должно быть сделано ...
Есть ли причина, по которой varchar имеет типы данных NULL?
0

собственный тип .NET. Это делает работу большую часть времени. Если у меня угловой шкаф, я просто напишу быструю вспомогательную функцию.

int i = dataReader.GetSqlInt32(0).Value;
3

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

dt.Columns[i].DataType.UnderlyingSystemType

dt - dataTable

Это вернет тип CLR для соответствующего столбца. Надеюсь, это поможет, и кстати, это мой первый ответ на стекoverflow

0

что нет встроенного для этого, но вы можете использовать VS для генерации классов для ваших таблиц, а затем попытаться редактировать их

3

но отвечает на общий связанный вопрос. Как только у вас естьIDataReader ты можешь позвонитьIDataRecord.GetFieldType(int) чтобы "получить"Type информация, соответствующая типуObject это будет возвращено изGetValue. & Quot;

Если у вас есть объект, который был прочитан из поля, вы также можете использовать SqlMetaData.InferFromValue (msdn.microsoft.com/en-us/library/… чтобы определить его тип.
0

что вы обсуждаете написание оператора 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 
    [email protected]
order by b.colorder

Теперь вы просто перечислите DataTable вместо более длинного оператора.

2

Wizardby, Тем не менее, он сопоставляется с так называемым «родным» типы данных дляDbType, которые затем легко преобразовать в типы CLR. Если это подходит, вам потребуется соответствующийIDbTypeMapper - илиSqlServer2000TypeMapper или жеSqlServer2005TypeMapper.

5
    internal Type type(SqlDbType sqltype)
    {
        Type resulttype = null;
        Dictionary<SqlDbType, Type> Types = new Dictionary<SqlDbType, Type>();
        Types.Add(SqlDbType.BigInt, typeof(Int64));
        Types.Add(SqlDbType.Binary, typeof(Byte[]));
        Types.Add(SqlDbType.Bit, typeof(Boolean));
        Types.Add(SqlDbType.Char, typeof(String));
        Types.Add(SqlDbType.Date, typeof(DateTime));
        Types.Add(SqlDbType.DateTime, typeof(DateTime));
        Types.Add(SqlDbType.DateTime2, typeof(DateTime));
        Types.Add(SqlDbType.DateTimeOffset, typeof(DateTimeOffset));
        Types.Add(SqlDbType.Decimal, typeof(Decimal));
        Types.Add(SqlDbType.Float, typeof(Double));
        Types.Add(SqlDbType.Image, typeof(Byte[]));
        Types.Add(SqlDbType.Int, typeof(Int32));
        Types.Add(SqlDbType.Money, typeof(Decimal));
        Types.Add(SqlDbType.NChar, typeof(String));
        Types.Add(SqlDbType.NText, typeof(String));
        Types.Add(SqlDbType.NVarChar, typeof(String));
        Types.Add(SqlDbType.Real, typeof(Single));
        Types.Add(SqlDbType.SmallDateTime, typeof(DateTime));
        Types.Add(SqlDbType.SmallInt, typeof(Int16));
        Types.Add(SqlDbType.SmallMoney, typeof(Decimal));
        Types.Add(SqlDbType.Text, typeof(String));
        Types.Add(SqlDbType.Time, typeof(TimeSpan));
        Types.Add(SqlDbType.Timestamp, typeof(Byte[]));
        Types.Add(SqlDbType.TinyInt, typeof(Byte));
        Types.Add(SqlDbType.UniqueIdentifier, typeof(Guid));
        Types.Add(SqlDbType.VarBinary, typeof(Byte[]));
        Types.Add(SqlDbType.VarChar, typeof(String));
        Types.TryGetValue(sqltype, out resulttype);
        return resulttype;
    }

    internal SqlDbType type(Type systype)
    {
        SqlDbType resulttype = SqlDbType.NVarChar;
        Dictionary<Type, SqlDbType> Types = new Dictionary<Type, SqlDbType>();
        Types.Add(typeof(Boolean), SqlDbType.Bit);
        Types.Add(typeof(String), SqlDbType.NVarChar);
        Types.Add(typeof(DateTime), SqlDbType.DateTime);
        Types.Add(typeof(Int16), SqlDbType.Int);
        Types.Add(typeof(Int32), SqlDbType.Int);
        Types.Add(typeof(Int64), SqlDbType.Int);
        Types.Add(typeof(Decimal), SqlDbType.Float);
        Types.Add(typeof(Double), SqlDbType.Float);
        Types.TryGetValue(systype, out resulttype);
        return resulttype;
    }
Кто-нибудь знает, еслиDictionary.TryGetValue() этот подход, показанный здесь, быстрее или медленнее, чемswitch...case appoach показано в другом месте в этой теме?
0

чтобы конструктор VS сделал это для вас? Если проект не должен адаптироваться во время выполнения к различным схемам, то вы должны использовать методы генерации кода для создания ваших классов, например, встроенные конструкторы (т.е. наборы типизированных данных) или пользовательские (схема-> XML-> XSLT- & GT; .cs).

Это тоже правильный подход. Грег уже дал хороший ответ. Обычно я рекомендую также рассмотреть возможность использования потоковых типов для больших типов (n / varchar / varbinary (max) и xml), но вы говорите, что используете SQL2K, поэтому он не применяется).
Он должен адаптироваться к различным схемам. Я пишу генератор, который принимает имя SP и генерирует класс C # из входных и выходных параметров, используя SQL-DMO (SQL 2000) Chris McCall

Похожие вопросы