views:

612

answers:

5

Can anyone show me a way of converting SQL Server data-types (varchar for example) to .Net data-types (String for example). I'm assuming that automatic conversion is not possible? I have an 'EntityProperty' object and would like it to have an appropriate 'Type' property (string, decimal, int32 etc), at the moment this property is just a string - 'int32' for example.

A little background: I'm using SQL DMO in an internal code generation app to query a database and generate a stored procedure based DAL from the database. Being an internal app I can take quite a few shortcuts and make quite a few assumptions. To get the app working at the moment this data-type conversion is handled by a Select Case statement which just converts the types to strings and generates a set of properties based on these strings but I would prefer a little more flexibility in being able to handle the types (use of TypeOf etc).

Anyone worked on something similar?

I know EF, nHibernate, Subsonic etc could do all this for me but in this case, for various reasons, I am having to roll my own. :)

+2  A: 

There is no way to "automatically" perform the type conversion. In fact, most ORM libraries rely on the actual property type used in the destination entity class in order to perform the mapping.

I would use the SQL-CLR Type Mapping from the Linq to SQL documentation as a starting point for building manual mapping code. In many cases there will be more than one valid mapping.

Aaronaught
+1  A: 

Or you could a table for your automatic translation and than use those values ( this is a preliminary one, not largely tested ... ) :

and USED IT DIRECTLY FOR CLASS GENERATION or even if you like generate the classes for the whole db

        /****** 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'short', 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;
YordanGeorgiev
I cringe whenever I see CLR type names in a database. It's a perfect example of http://thedailywtf.com/Articles/Soft_Coding.aspx.
Aaronaught
Depends on the usage. This one is used for many purposes one of which is code generation ...
YordanGeorgiev
+ if you have multiprovider system ... e.g. using one db for configuring different RDBMS ....
YordanGeorgiev
+1  A: 

I've done something like this in the other direction, using a Dictionary of System.Type objects to SQL type names.

dan04
This is kind of what I've got but am using strings rather than the actual types.
Simon
+1  A: 

I know EF, nHibernate, Subsonic etc could do all this for me but in this case, for various reasons, I am having to roll my own. :)

Why don't you use SubSonic or one of the other ORM mapping tools to define working conversions between Sql datatypes and .Net datatypes - and then roll your own solution using this information on the conversions as a basis?

I'm assuming that you can't use third-party software in the solution - but you can in coming to a solution.

amelvin
+2  A: 

The reason hard coding is a Bad Thing is only because when you put things in code that change, it's annoying (and expensive) - there's no other reason. Things that don't change, like pi, or the list of weekdays, can be hard-coded to your heart's content, and you won't incur any extra development cost as a result.

So this problem isn't so much about not maintaining a manual mapping table - in code if necessary - as it is about only maintaining the mapping table in one place.

We rolled our own data access class, several years ago now. And sure, we convert manually (in a VB.NET Select Case statement) from .NET types to SQL types. I think it changed once, when we had to add Enum types.

That's once, in about four years. We do a release a week, on average - guess how worried we are about the 'overhead' of hard coding the .NET -> SQL type mapping?

Do it in one place. Ensure that everything uses it. And then forget about it. There are other, much tougher problems to solve.

ChrisA
I agree, I wasn't particularly concerned with the hard-coding aspect, I just wondered if I was missing something with my Select Case approach. :)
Simon