Asignación de tipos entre CLR y SQL
En LINQ to SQL, el modelo de datos de una base de datos relacional se asigna a un modelo de objetos expresado en el lenguaje de programación que prefiera. Cuando la aplicación se ejecuta, LINQ to SQL convierte las consultas integradas del lenguaje del modelo de objetos a SQL y las envía a la base de datos para su ejecución. Cuando la base de datos devuelve los resultados, LINQ to SQL los vuelve a convertir en objetos con los que pueda trabajar en su propio lenguaje de programación.
Para convertir los datos entre el modelo de objetos y la base de datos, se debe definir una asignación de tipos. LINQ to SQL utiliza una asignación de tipos para que cada tipo de Common Language Runtime (CLR) se corresponda con un tipo de SQL Server concreto. Las asignaciones de tipos y otra información de asignación, como las relaciones de tablas y estructuras de bases de datos, se pueden definir en el modelo de objetos con una asignación basada en atributos. Opcionalmente, la información de asignación se puede especificar fuera del modelo de objetos con un archivo de asignación externo. Para más información, consulte Asignación basada en atributos y Asignación externa.
En este tema se tratan los puntos siguientes:
Matriz de comportamiento de la asignación de tipos en tiempo de ejecución
Diferencias de comportamiento entre la ejecución de CLR y SQL
Asignación de tipos predeterminados
Puede crear automáticamente el modelo de objetos o el archivo de asignación con Object Relational Designer o la herramienta de línea de comandos SQLMetal. Las asignaciones de tipos predeterminadas de estas herramientas definen qué tipos de CLR se deben elegir para asignarlos a columnas en la base de datos SQL Server. Para más información sobre el uso de estas herramientas, consulte Crear el modelo de objetos.
También puede utilizar el método CreateDatabase para crear una base de datos de SQL Server según la información de asignación del modelo de objetos o del archivo de asignación externo. Las asignaciones de tipos predeterminadas del método CreateDatabase definen qué tipo de columnas de SQL Server se deben crear para asignarlas a los tipos de CLR en el modelo de objetos. Para más información, consulte Cómo crear dinámicamente una base de datos.
Matriz de comportamiento de la asignación de tipos en tiempo de ejecución
En el diagrama siguiente se muestra el comportamiento de las asignaciones de tipos específicos que se espera en tiempo de ejecución, cuando los datos se recuperan de la base de datos o se guardan en ella. Con la excepción de la serialización, LINQ to SQL no admite la asignación entre los tipos de datos de CLR o SQL Server no especificados en esta matriz. Para más información sobre la compatibilidad con la serialización, consulte Serialización binaria.
Nota:
Algunas asignaciones de tipos pueden tener como resultado excepciones de desbordamiento o de pérdida de datos mientras se convierten a la base de datos o desde ella.
Asignación de tipos personalizados
Con LINQ to SQL, no está limitado a usar las asignaciones de tipos predeterminadas de Object Relational Designer, SQLMetal y el método CreateDatabase. Puede crear asignaciones de tipos personalizadas especificándolas explícitamente en un archivo DBML. Después, puede usar ese archivo para crear el código del modelo de objetos y el archivo de asignación. Para más información, consulte Asignaciones de tipos personalizadas entre SQL y CLR.
Diferencias de comportamiento entre la ejecución de CLR y SQL
Debido a las diferencias entre CLR y SQL Server en cuanto a la precisión y la ejecución, puede recibir diferentes resultados o experimentar un comportamiento distinto en función de dónde se realicen los cálculos. Los cálculos realizados en las consultas LINQ to SQL se traducen, de hecho, a Transact-SQL y después se ejecutan en la base de datos de SQL Server. Los cálculos realizados fuera de las consultas LINQ to SQL se ejecutan en el contexto de CLR.
Por ejemplo, a continuación se indican algunas diferencias de comportamiento entre CLR y SQL Server:
SQL Server ordena ciertos tipos de datos de forma diferente a los datos del tipo equivalente en CLR. Por ejemplo, los datos de SQL Server del tipo
UNIQUEIDENTIFIER
se ordenan de forma diferente a los datos de CLR del tipo System.Guid.SQL Server trata ciertas operaciones de comparación de cadenas de forma diferente a CLR. En SQL Server, el comportamiento de comparación de cadenas depende de la configuración de intercalación del servidor. Para más información, consulte Trabajar con intercalaciones.
SQL Server puede devolver valores diferentes a los que devuelve CLR para algunas funciones asignadas. Por ejemplo, las funciones de igualdad tendrán resultados distintos porque SQL Server considera que dos cadenas son iguales si solo se diferencian en el espacio en blanco final, mientras que CLR considera que no son iguales.
Asignación de enumeración
LINQ to SQL admite la asignación del tipo System.Enum de CLR a tipos de SQL Server de dos maneras:
Asignación a tipos SQL numéricos (
TINYINT
,SMALLINT
,INT
,BIGINT
)Al asignar un tipo System.Enum de CLR a un tipo numérico de SQL, el valor entero subyacente del tipo System.Enum de CLR se asigna al valor de la columna de base de datos de SQL Server. Por ejemplo, si un elemento System.Enum denominado
DaysOfWeek
contiene un miembro denominadoTue
con un valor entero subyacente de 3, ese miembro se asigna a un valor de base de datos de 3.Asignación a tipos SQL de texto (
CHAR
,NCHAR
,VARCHAR
,NVARCHAR
)Al asignar un tipo System.Enum de CLR a un tipo de texto de SQL, el valor de la base de datos SQL se asigna a los nombres de los miembros System.Enum de CLR. Por ejemplo, si un tipo System.Enum denominado
DaysOfWeek
contiene un miembro denominadoTue
con un valor entero subyacente de 3, ese miembro se asigna a un valor de base de datos deTue
.
Nota:
Cuando los tipos de texto de SQL se asignan a System.Enum de CLR, solo se incluyen los nombres de los miembros Enum en la columna de SQL asignada. No se admiten otros valores en la columna de SQL asignada a Enum.
Object Relational Designer y la herramienta de línea de comandos SQLMetal no pueden asignar automáticamente un tipo SQL a una clase Enum de CLR. Debe configurar explícitamente esta asignación personalizando un archivo DBML para que lo usen Object Relational Designer y SQLMetal. Para más información acerca de la asignación de tipos personalizados, consulte Asignaciones de tipos personalizadas entre SQL y CLR.
Puesto que una columna SQL de enumeración tendrá el mismo tipo que el resto de las columnas numéricas y de texto, estas herramientas no reconocerán el intento y la asignación se realizará de forma predeterminada tal y como se describe en las siguientes secciones Asignación numérica y Asignación de texto y XML. Para más información sobre el código generador con el archivo DBML, consulte Generación de código en LINQ to SQL.
El método DataContext.CreateDatabase crea una columna de SQL de tipo numérico para asignar un tipo System.Enum de CLR.
Asignación numérica
LINQ to SQL permite asignar muchos tipos numéricos de CLR y SQL Server. En la tabla siguiente se muestran los tipos de CLR que Object Relational Designer y SQLMetal seleccionan al crear un modelo de objetos o un archivo de asignación externo de acuerdo con la base de datos.
Tipo de datos de SQL Server | Asignación de tipos de CLR predeterminada usada por Object Relational Designer y SQLMetal |
---|---|
BIT |
System.Boolean |
TINYINT |
System.Int16 |
INT |
System.Int32 |
BIGINT |
System.Int64 |
SMALLMONEY |
System.Decimal |
MONEY |
System.Decimal |
DECIMAL |
System.Decimal |
NUMERIC |
System.Decimal |
REAL/FLOAT(24) |
System.Single |
FLOAT/FLOAT(53) |
System.Double |
En la tabla siguiente se muestran las asignaciones de tipos predeterminadas que el método DataContext.CreateDatabase utiliza para definir qué tipo de columnas de SQL se deben crear para asignarlas a los tipos de CLR definidos en el modelo de objetos o en el archivo de asignación externo.
Tipo CLR | Tipo predeterminado de SQL Server utilizado por DataContext.CreateDatabase |
---|---|
System.Boolean | BIT |
System.Byte | TINYINT |
System.Int16 | SMALLINT |
System.Int32 | INT |
System.Int64 | BIGINT |
System.SByte | SMALLINT |
System.UInt16 | INT |
System.UInt32 | BIGINT |
System.UInt64 | DECIMAL(20) |
System.Decimal | DECIMAL(29,4) |
System.Single | REAL |
System.Double | FLOAT |
Hay muchas otras asignaciones de tipos numéricos entre las que puede elegir, pero algunas pueden tener como resultado excepciones de desbordamiento o de pérdida de datos mientras se trasladan a la base de datos o desde ella. Para más información, consulte Matriz de comportamiento de la asignación de tipos en tiempo de ejecución.
Tipos Decimal y Money
La precisión predeterminada del tipo DECIMAL
de SQL Server (18 dígitos decimales a la derecha y a la izquierda del separador decimal) es menor que la precisión del tipo de CLR System.Decimal con el que se empareja de forma predeterminada. Esto puede producir una pérdida de precisión cuando los datos se guardan en la base de datos. Sin embargo, puede ocurrir exactamente lo contrario si el tipo DECIMAL
de SQL Server se configura con más de 29 dígitos de precisión. Cuando se ha configurado un tipo DECIMAL
de SQL Server con mayor precisión que el tipo System.Decimal de CLR, la pérdida de precisión se produce al recuperar los datos de la base de datos.
Los tipos MONEY
y SMALLMONEY
de SQL Server, que también están emparejados con el tipo System.Decimal de CLR de forma predeterminada, tienen mucha menos precisión, por lo que pueden producirse excepciones de desbordamiento o de pérdida de datos al guardar los datos en la base de datos.
Asignación de texto y XML
También hay muchos tipos XML y basados en texto que se pueden asignar con LINQ to SQL. En la tabla siguiente se muestran los tipos de CLR que Object Relational Designer y SQLMetal seleccionan al crear un modelo de objetos o un archivo de asignación externo de acuerdo con la base de datos.
Tipo de datos de SQL Server | Asignación de tipos de CLR predeterminada usada por Object Relational Designer y SQLMetal |
---|---|
CHAR |
System.String |
NCHAR |
System.String |
VARCHAR |
System.String |
NVARCHAR |
System.String |
TEXT |
System.String |
NTEXT |
System.String |
XML |
System.Xml.Linq.XElement |
En la tabla siguiente se muestran las asignaciones de tipos predeterminadas que el método DataContext.CreateDatabase utiliza para definir qué tipo de columnas de SQL se deben crear para asignarlas a los tipos de CLR definidos en el modelo de objetos o en el archivo de asignación externo.
Tipo CLR | Tipo predeterminado de SQL Server utilizado por DataContext.CreateDatabase |
---|---|
System.Char | NCHAR(1) |
System.String | NVARCHAR(4000) |
System.Char[] | NVARCHAR(4000) |
Tipo personalizado que implementa Parse() y ToString() |
NVARCHAR(MAX) |
Hay muchas otras asignaciones de XML y basadas en texto entre las que puede elegir, pero algunas pueden tener como resultado excepciones de desbordamiento o de pérdida de datos mientras se trasladan a o desde la base de datos. Para más información, consulte Matriz de comportamiento de la asignación de tipos en tiempo de ejecución.
Tipos XML
El tipo de datos XML
de SQL Server está disponible a partir de Microsoft SQL Server 2005. Puede asignar el tipo de datos XML
de SQL Server a XElement, XDocument o String. Si la columna almacena fragmentos XML que no se pueden leer en XElement, dicha columna debe asignarse a String para evitar errores en tiempo de ejecución. Entre los fragmentos XML que se deben asignar a String se incluyen los siguientes:
Una secuencia de elementos XML
Atributos
Identificadores públicos (PI)
Comentarios
Aunque puede asignar XElement y XDocument a SQL Server como se muestra en Matriz de comportamiento de la asignación de tipos en tiempo de ejecución, el método DataContext.CreateDatabase no dispone de ninguna asignación predeterminada de tipos de SQL Server para estos tipos.
Tipos personalizados
Si una clase implementa Parse()
y ToString()
, el objeto se puede asignar a cualquier tipo de texto de SQL (CHAR
, NCHAR
, VARCHAR
, NVARCHAR
, TEXT
, NTEXT
, XML
). El objeto se almacena en la base de datos enviando el valor devuelto por ToString()
a la columna de base de datos asignada. El objeto se reconstruye invocando a Parse()
en la cadena devuelta por la base de datos.
Nota
LINQ to SQL no admite la serialización mediante System.Xml.Serialization.IXmlSerializable.
Asignación de fecha y hora
Con LINQ to SQL, se pueden asignar muchos tipos de fecha y hora de SQL Server. En la tabla siguiente se muestran los tipos de CLR que Object Relational Designer y SQLMetal seleccionan al crear un modelo de objetos o un archivo de asignación externo de acuerdo con la base de datos.
Tipo de datos de SQL Server | Asignación de tipos de CLR predeterminada usada por Object Relational Designer y SQLMetal |
---|---|
SMALLDATETIME |
System.DateTime |
DATETIME |
System.DateTime |
DATETIME2 |
System.DateTime |
DATETIMEOFFSET |
System.DateTimeOffset |
DATE |
System.DateTime |
TIME |
System.TimeSpan |
En la tabla siguiente se muestran las asignaciones de tipos predeterminadas que el método DataContext.CreateDatabase utiliza para definir qué tipo de columnas de SQL se deben crear para asignarlas a los tipos de CLR definidos en el modelo de objetos o en el archivo de asignación externo.
Tipo CLR | Tipo predeterminado de SQL Server utilizado por DataContext.CreateDatabase |
---|---|
System.DateTime | DATETIME |
System.DateTimeOffset | DATETIMEOFFSET |
System.TimeSpan | TIME |
Hay muchas otras asignaciones de fecha y hora entre las que puede elegir, pero algunas pueden tener como resultado excepciones de desbordamiento o de pérdida de datos mientras se trasladan a o desde la base de datos. Para más información, consulte Matriz de comportamiento de la asignación de tipos en tiempo de ejecución.
Nota
Los tipos de SQL Server DATETIME2
, DATETIMEOFFSET
, DATE
y TIME
están disponibles a partir de Microsoft SQL Server 2008. LINQ to SQL admite la asignación a estos tipos nuevos a partir del Service Pack 1 de .NET Framework 3.5.
System.Datetime
El intervalo y la precisión del tipo System.DateTime de CLR son mayores que el intervalo y la precisión del tipo DATETIME
de SQL Server, que es la asignación de tipos predeterminada para el método DataContext.CreateDatabase. Para evitar las excepciones relacionadas con los datos que están fuera del intervalo de DATETIME
, utilice DATETIME2
, que está disponible a partir de Microsoft SQL Server 2008. DATETIME2
puede alcanzar la precisión y el intervalo del tipo de CLR System.DateTime.
Las fechas de SQL Server no disponen del concepto de TimeZone, que es una característica totalmente admitida en CLR. Los valores de TimeZone se guardan tal como están en la base de datos sin conversión de TimeZone, independientemente de la información de DateTimeKind original. Cuando los valores DateTime se recuperan de la base de datos, su valor se carga tal cual en DateTime, con un valor DateTimeKind de Unspecified. Para más información acerca de los métodos System.DateTime admitidos, consulte Métodos System.DateTime.
System.TimeSpan
Microsoft SQL Server 2008 y .NET Framework 3.5 SP1 permiten asignar el tipo System.TimeSpan de CLR al tipo TIME
de SQL Server. Sin embargo, existe una gran diferencia entre el intervalo que admite el tipo System.TimeSpan de CLR y el que admite el tipo TIME
de SQL Server. La asignación de valores menores que 0 horas o mayores que 23:59:59.9999999 horas al tipo TIME
de SQL producirá excepciones de desbordamiento. Para más información, consulte Métodos System.TimeSpan.
En Microsoft SQL Server 2000 y SQL Server 2005, no se pueden asignar campos de base de datos a TimeSpan. Sin embargo, se admiten las operaciones en TimeSpan porque se pueden devolver valores TimeSpan a partir de la sustracción de DateTime o se pueden incluir en una expresión como una variable literal o una variable enlazada.
Asignación binaria
Hay muchos tipos de SQL Server que se pueden asignar al tipo System.Data.Linq.Binary de CLR. En la tabla siguiente se muestran los tipos de SQL Server que provocan que Object Relational Designer y SQLMetal definan un tipo System.Data.Linq.Binary de CLR al crear un modelo de objetos o un archivo de asignación externo de acuerdo con la base de datos.
Tipo de datos de SQL Server | Asignación de tipos de CLR predeterminada usada por Object Relational Designer y SQLMetal |
---|---|
BINARY(50) |
System.Data.Linq.Binary |
VARBINARY(50) |
System.Data.Linq.Binary |
VARBINARY(MAX) |
System.Data.Linq.Binary |
VARBINARY(MAX) con el atributo FILESTREAM |
System.Data.Linq.Binary |
IMAGE |
System.Data.Linq.Binary |
TIMESTAMP |
System.Data.Linq.Binary |
En la tabla siguiente se muestran las asignaciones de tipos predeterminadas que el método DataContext.CreateDatabase utiliza para definir qué tipo de columnas de SQL se deben crear para asignarlas a los tipos de CLR definidos en el modelo de objetos o en el archivo de asignación externo.
Tipo CLR | Tipo predeterminado de SQL Server utilizado por DataContext.CreateDatabase |
---|---|
System.Data.Linq.Binary | VARBINARY(MAX) |
System.Byte | VARBINARY(MAX) |
System.Runtime.Serialization.ISerializable | VARBINARY(MAX) |
Hay muchas otras asignaciones binarias entre las que puede elegir, pero algunas pueden tener como resultado excepciones de desbordamiento o de pérdida de datos mientras se trasladan a o desde la base de datos. Para más información, consulte Matriz de comportamiento de la asignación de tipos en tiempo de ejecución.
SQL Server FILESTREAM
El atributo FILESTREAM
para las columnas VARBINARY(MAX)
está disponible a partir de Microsoft SQL Server 2008; se le pueden asignar elementos con LINQ to SQL a partir del Service Pack 1 de .NET Framework 3.5.
Aunque puede asignar columnas VARBINARY(MAX)
con el atributo FILESTREAM
a objetos Binary, el método DataContext.CreateDatabase no puede crear columnas automáticamente con el atributo FILESTREAM
. Para más información sobre FILESTREAM
, consulte Información general de FILESTREAM.
Serialización binaria
Si una clase implementa la interfaz ISerializable, se puede serializar un objeto en cualquier campo binario de SQL (BINARY
, VARBINARY
, IMAGE
). El objeto se serializa o deserializa de acuerdo con la forma en que se haya implementado la interfaz ISerializable. Para más información, consulte Serialización binaria.
Asignaciones varias
En la tabla siguiente se muestran las asignaciones de tipos predeterminadas para varios tipos que aún no se han mencionado. En la tabla siguiente se muestran los tipos de CLR que Object Relational Designer y SQLMetal seleccionan al crear un modelo de objetos o un archivo de asignación externo de acuerdo con la base de datos.
Tipo de datos de SQL Server | Asignación de tipos de CLR predeterminada usada por Object Relational Designer y SQLMetal |
---|---|
UNIQUEIDENTIFIER |
System.Guid |
SQL_VARIANT |
System.Object |
En la tabla siguiente se muestran las asignaciones de tipos predeterminadas que el método DataContext.CreateDatabase utiliza para definir qué tipo de columnas de SQL se deben crear para asignarlas a los tipos de CLR definidos en el modelo de objetos o en el archivo de asignación externo.
Tipo CLR | Tipo predeterminado de SQL Server utilizado por DataContext.CreateDatabase |
---|---|
System.Guid | UNIQUEIDENTIFIER |
System.Object | SQL_VARIANT |
LINQ to SQL no admite ninguna otra asignación de tipos para estos tipos varios. Para más información, consulte Matriz de comportamiento de la asignación de tipos en tiempo de ejecución.