2010-03-21 10 views
7

¿Alguien me puede mostrar una forma de convertir los tipos de datos de SQL Server (varchar por ejemplo) a tipos de datos .Net (String, por ejemplo). Supongo que la conversión automática no es posible. Tengo un objeto 'EntityProperty' y me gustaría tener una propiedad 'Tipo' apropiada (cadena, decimal, int32, etc.), en este momento esta propiedad es solo una cadena - 'int32' por ejemplo.¿Cómo puedo convertir programáticamente tipos de datos SQL a tipos de datos .Net?

Un poco de historia: estoy usando SQL DMO en una aplicación de generación de código interno para consultar una base de datos y generar un procedimiento almacenado basado en DAL de la base de datos. Al ser una aplicación interna, puedo tomar bastantes atajos y hacer bastantes suposiciones. Para que la aplicación funcione en el momento, esta conversión de tipo de datos es manejada por una declaración Select Case que simplemente convierte los tipos en cadenas y genera un conjunto de propiedades basadas en estas cadenas, pero yo preferiría un poco más de flexibilidad para poder manejar los tipos (uso de TypeOf, etc.).

¿Alguien trabajó en algo similar?

Sé que EF, nHibernate, Subsonic etc. podrían hacer todo esto por mí, pero en este caso, por diversas razones, estoy teniendo que hacer mi propia versión. :)

+0

@Simon: La pérdida de reputación no está relacionada; ha habido un cambio en todo el sitio en el sistema de rep junto con un recalc retroactivo. http://blog.stackoverflow.com/2010/03/the-great-reputation-recalc-begins/ –

Respuesta

2

He hecho algo como esto en la otra dirección, usando un Diccionario de objetos System.Type a nombres de tipo SQL.

+0

Esto es algo de lo que tengo pero estoy usando cadenas en lugar de los tipos reales. – Simon

4

No hay forma de realizar la conversión de tipo "automáticamente". De hecho, la mayoría de las bibliotecas ORM dependen del tipo de propiedad real utilizado en la clase de entidad de destino para realizar la asignación.

Utilizaría el SQL-CLR Type Mapping de la documentación de Linq a SQL como punto de partida para crear código de mapeo manual. En muchos casos, habrá más de un mapeo válido.

2

O usted podría una mesa para su traducción automática y de utilizar esos valores (esto es preliminar, no se ha probado en gran medida ...):

y USED IT DIRECTLY FOR CLASS GENERATION o incluso si te gusta 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; 
+2

Me avergüenzo cada vez que veo los nombres de tipo CLR en una base de datos. Es un ejemplo perfecto de http://thedailywtf.com/Articles/Soft_Coding.aspx. – Aaronaught

+0

Depende del uso. Este se usa para muchos propósitos, uno de los cuales es la generación de código ... –

+0

+ si tiene un sistema multiproveedor ... p. usando un DB para configurar diferentes RDBMS .... –

1

Sé que EF, nHibernate, Subsonic etc. podrían hacer todo esto por mí, pero en este caso, por diversas razones, estoy teniendo que hacer mi propia versión. :)

¿Por qué no usar SubSonic o una de las otras herramientas de mapeo ORM para definir las conversiones de trabajo entre los tipos de datos SQL y tipos de datos .Net - y luego rodar su propia solución utilizando esta información en las conversiones de base ?

Supongo que no puede usar software de terceros en la solución, pero puede llegar a una solución.

6

La razón por la cual la codificación dura es una cosa mala es solo porque cuando pones cosas en el código que cambian, es molesto (y costoso); no hay otra razón. Las cosas que no cambian, como pi, o la lista de días de la semana, se pueden codificar de forma rígida para su corazón y, como resultado, no incurrirá en ningún costo de desarrollo adicional.

De modo que este problema no se trata tanto de no mantener una tabla de asignación manual, en el código si es necesario, sino de mantener la tabla de asignación en un solo lugar.

Hemos robado nuestra propia clase de acceso a datos, hace varios años. Y claro, convertimos manualmente (en un VB.Declaración NET Select Case) de tipos .NET a tipos SQL. Creo que cambió una vez, cuando tuvimos que agregar tipos Enum.

Eso es una vez, en unos cuatro años. Hacemos un lanzamiento por semana, en promedio, ¿adivinan qué tan preocupados estamos con la 'sobrecarga' de la codificación dura del mapeo de tipo .NET -> SQL?

Hazlo en un solo lugar. Asegúrese de que todo lo use. Y luego olvídate de eso. Hay otros problemas mucho más difíciles de resolver.

+1

Acepto, no estaba particularmente preocupado con el aspecto de la codificación rígida, solo me preguntaba si me estaba perdiendo algo con mi enfoque de Seleccionar caso. :) – Simon