Introducción
Los desarrolladores no vivimos aislados del mundo de las bases de datos, y necesitamos de ellas para poder trabajar. Como siempre nos tiene acostumbrado Microsoft, cada nueva versión del motor de base de datos, en este caso SQL Server 2008, viene con nuevas funcionalidades que potencian las aplicaciones y nos brindan un abanico más grande aún de posibilidades de solución a los desafíos del desarrollo. En este artículo daremos una recorrida por los aspectos más relevantes de las mejoras introducidas por SQL Server 2008 que los desarrolladores debemos conocer.
Tipo de Dato FileStream
A lo largo del tiempo, los desarrolladores hemos inventando variadas técnicas, para almacenar datos no estructurados como ser mapas de bits (bitmaps), archivos de texto, archivos de audio, etc. Algunas de ellas han sido, por ejemplo guardar en la base de datos la ruta donde el archivo se alojaba en el sistema de archivos (file system). Claro que esto trae problemas de seguridad, o de pérdidas de referencias por cambios en la ruta, o la necesidad de coordinar la transacción entre los dos recursos con DTC.
El tipo de dato FILESTREAM nos trae solución a aquellos problemas, permitiéndole a las aplicaciones utilizar las API de streaming con el mismo rendimiento que el sistema de archivos, y a su vez mantener una consistencia transaccional el mismo esquema de seguridad entre la información estructurada y la no estructurada.
La seguridad para los objetos almacenados en un campo del tipo FILESTREAM goza de los mismos privilegios que cualquier tipo de dato ya existente. Solo es necesario establecer los permisos a la tabla o la columna que lo contenga. Es decir, si el usuario tiene permisos de acceso a la columna correspondiente, podrá abrir el archivo asociado a ella.
El tipo de dato FILESTREAM es implementado como una columna varbinary(max), y totalmente integrado en el motor. Lo cual permite utilizar todas las técnicas de copias de respaldo y restauración para resguardar los datos.
Antes que nada es necesario habilitar el uso de FILESTREAM en el motor:
EXEC sp_filestream_configure
@enable_level = 3,
@share_name = "RecursoCompartidoSQL";
Donde @enable_level = 3, habilita el uso para T_SQL, acceso a sistema de archivos local y remoto; y @share_name = "RecursoCompartidoSQL" es el nombre del recurso compartido en el sistema de archivos.
He aquí un ejemplo de cómo crear una tabla con un campo FILESTEAM y la sintaxis para insertar datos:
--Crea un tabla que contiene infromación adicional como FILESTREAM
CREATE TABLE dbo.Persona
(
ID int,
Nombre varchar(100),
InfoAdicional varbinary(max) FILESTREAM
);
GO
--Agrego el registro en la tabla
Insert into dbo.Persona
Values(
1,
'Juan Perez',
Cast ('Aqui información adicional' As varbinary(max)))
Go
Es aconsejable utilizar el tipo de dato FILESTREAM cuando los objetos a almacenar son en promedio mayor a 1 Mb, y su acceso rápido de lectura es un punto a considerar. Para objetos de tamaño menor, es recomendable seguir utilizando el tipo de dato varbinary(max), el cual provee un rendimiento menor en estos casos.
Inicialización en línea y asignación compuesta de variables
Una pequeña mejora introduce SQL Server 2008 al lenguaje T-SQL respecto de la inicialización y asignación de variables. Cuántas veces hemos deseado escribir código de la siguiente manera:
declare
@fecha datetime = getdate(),
@edad int = 36,
@nombre varchar(100) = 'carlos';
-- Muestro los valores...
select @fecha, @edad, @nombre
En versiones anteriores hubiésemos obtenido el siguiente error de sintaxis:
Msg 139, Level 15, State 1, Line 0Cannot assign a default value to a local variable.
Ahora, en SQL Server 2008 es completamente válido.
Veamos esta sintaxis:
-- Incremento i, agrego algo al nombre....
select @edad += 1, @nombre += ' walzer';
-- Muestro los valores...
select @edad, @nombre;
Estos operadores funcionan incluso con sentencias DML y columnas. Veamos la forma de incrementar en 100 la columna de una tabla:
update tabla set comlumna += 100;
o realizar la operación entre dos columnas:
update tabla set columna1 += columna2;
Comando Merge
Este comando se lo conoce informalmente como UPSERT ya que permite hacer inserciones o actualizaciones (UPDATE INSERT) de acuerdo a la existencia del registro.
Este ejemplo insertará un registro en la tabla Destino si no tiene contraparte en la tabla Fuente, de existir se actualizará el correspondiente:
MERGE INTO Destino D
USING Fuente F ON F.Id = D.Id
WHEN MATCHED THEN UPDATE
SET D.Cantidad = F.cantidad
WHEN NOT MATCHED THEN INSERT (Id, Cantidad)
VALUES (F.Id, F.Cantidad)
Nuevos tipos de datos DateTime
Antes de contarles los nuevos tipos de dato fecha que nos brinda SQL Server 2008, hagamos un repaso de los ya existentes. El tipo de dato fecha SMALLDATETIME almacena fecha y hora con una precisión de 1 minuto, requiriendo 4 bytes. DATETIME es el más usado y almacena fecha y hora en un rango entre 01-01-1753 a 9999-12-31, y necesita 8 bytes.
Veamos ahora los nuevos tipos:
TIME: El tipo de dato TIME fue pensado para almacenar la hora del día con gran precisión, y no contiene información de fecha.
DATE: Este es muy usado para almacenar fechas sin su hora correspondiente, en un rango de 0001-01-01 a 9999-12-31, consumiendo 3 bytes.
DATETIME2: Este tipo de dato fecha/hora fue concebido para almacenar valores con gran precisión. Su capacidad es variable y se puede ajustar a la necesidad. DATETIME2 respeta el calendario gregoriano y entiende de los cambios de hora estacionales (daytime saving). Al momento de su definición podemos especificar la fracción de segundos que queremos almacenar:
SELECT CAST('2007-10-20 20:30:05.1234567' as DATETIME2)
Resultado: 2007-10-20 20:30:05.1234567
SELECT CAST('2007-10-20 20:30:05.1234567' as DATETIME2(4))
Resultado: 2007-10-20 20:30:05.1235
DATETIMEOFFSET: Es el tipo de dato fecha/hora más completo de su familia. Podemos almacenar valores de fecha y hora con gran precisión, junto a información de husos horarios. Es decir que podemos almacenar la fecha, y especificar el huso como: GMT -3:00 para Buenos Aires, o GMT +01:00 para Madrid. El rango de fechas va desde 0001-01-01 a 9999-12-31, el de horas de 00:00:00 a 23:59:59.9999999 y el desplazamiento horario de -14:00 a +14:00. Al igual que DATETIME2, la precisión puede especificarse en su definición:
SELECT CAST('2007-10-20 20:30:05.1234567 +5:0' as DATETIMEOFFSET)
Resultado: 2007-10-20 20:30:05.1234567 +05:00
SELECT CAST('2007-10-20 20:30:05.1234567 +5:0' as DATETIMEOFFSET(3))
Resultado: 2007-10-20 20:30:05.123 +05:00
Parámetros del tipo Tabla
Existe un nuevo tipo de parámetro en SQL Server 2008 del tipo Tabla, el cual puede ser declarado como tipo de una tabla previamente definida. Este parámetro puede ser utilizado para enviar varias filas de información a una sentencia T-SQL o rutina. Son similares a los vectores en OLE DB y ODBC pero con mayor flexibilidad.
Los parámetros del tipo tabla vienen a suplir la comúnmente usada técnica de creación de tablas temporales, agregando las siguientes ventajas:
- Son fuertemente tipificadas
- Se puede especificar un ordenamiento y clave única
- Reduce las llamadas al servidor
- Evita la re compilación de la sentencia
- No necesita de un bloqueo desde el cliente para inicializar los valores de la tabla.
Veamos un ejemplo de uso, del lado del servidor:
create type dbo.miArray
as table ( SalesOrderID int, ProductID int
, primary key (SalesOrderID, ProductID)
)
go
declare @mi_variable as dbo.miArray
insert @mi_variable
select top 10 sh.SalesOrderID, ProductID from SalesLT.SalesOrderHeader sh
join SalesLT.SalesOrderDetail sd on sh.SalesOrderID = sd.SalesOrderID
go
create proc dbo.ObtenerPedidos
@lista dbo.miArray readonly as
select * from SalesLT.SalesOrderHeader sh
join SalesLT.SalesOrderDetail sd on sh.SalesOrderID = sd.SalesOrderID
join @lista l on sh.SalesOrderID = l.SalesOrderID
and sd.ProductID = l.ProductID
go
dbcc dropcleanbuffers
dbcc freeproccachego
declare @mi_variable as dbo.miArray
insert @mi_variable
select sh.Sale sOrderID, ProductID from SalesLT.SalesOrderHeader sh
join SalesLT.SalesOrderDetail sd on sh.SalesOrderID = sd.SalesOrderID
select * from @mi_variable
exec dbo.ObtenerPedidos @mi_variable
go
El siguiente código Visual Basic.NET realiza la invocación al procedimiento almacenado definido anteriormente y muestra el resultado en una grilla.
Dim conn As New SqlConnection("Application Name=Test;Server=.;Integrated Security=SSPI;Database=AdventureWorksLT;")
Dim cmd As New SqlCommand()
cmd.Connection = conn
cmd.CommandText = "ObtenerPedidos"
cmd.CommandType = CommandType.StoredProcedurecmd.Connection.Open()
'Defino el tipo de dato del parámetro a pasar
Dim par As New SqlParameterpar.ParameterName = "@lista"
par.SqlDbType = SqlDbType.Structured
'Utilizo un ADO DataTable como estructura a pasar
Dim dt As New DataTable
dt.Columns.Add("SalesOrderID", GetType(Integer))
dt.Columns.Add("ProductID", GetType(Integer))
Dim drow As DataRow = dt.NewRow
drow(0) = 71774
drow(1) = 822
dt.Rows.Add(drow)
drow = dt.NewRow
drow(0) = 71774
drow(1) = 836
dt.Rows.Add(drow)
drow = dt.NewRow
drow(0) = 71776
drow(1) = 907
dt.Rows.Add(drow)
drow = dt.NewRow
drow(0) = 71780
drow(1) = 743
dt.Rows.Add(drow)
'Asigno le DataTable como valor del parámetro
par.Value = dt
'Paso el DataTable como parámetro en la invoación al procedimiento almacenado
cmd.Parameters.Add(par)
Dim tResult As New DataTable
tResult.Load(cmd.ExecuteReader)
DataGridView1.DataSource = tResultcmd.Connection.Close()
Desarrollo Dinámico
Existe un nuevo Lenguaje de Consultas Integrado LINQ (Language Integrated Query) en .NET Framework 3.5 el cual tiene soporte en SQL Server 2008. Además hay un soporte más eficiente para las entidades de datos de negocio (Business Data Entities) respecto de la sincronización de los datos. Estos tópicos más algunas mejoras en ADO.NET y Visual Studio se han catalogado como Desarrollo Dinámico.
Servicios de Entidades de Datos
La Inclusión de los Servicios de Entidades de Datos (Entity Data Services ) permiten ahora , con SQL Server 2008 y ADO.NET, poder crear objetos de negocio de alto nivel, por ejemplo Clientes o Facturas. Estas entidades se pueden utilizar y reemplazan el método estándar de devolver filas y tablas. Si estas utilizando un modelado basado en relación entre entidades, los objetos en SQL Server ahora acompañan tu modelo. Hay nuevas herramientas de ADO.NET que pueden tener acceso a estas entidades como ser el Lenguaje de Consultas Integrado LINQ to SQL.
Programar en un alto nivel de abstracción es altamente productivo y nos permite sacar buen provecho del modelo de entidad-relación. ADO.NET nos permite entonces programar y percibir a la información relacional como entidades de negocio.
LINQ
El Lenguaje de Consultas Integrado LINQ, nos permite realizar consultas a una fuente de datos utilizando lenguajes de programación manejados tales como Visual Basic.NET o C#, en lugar de usar sentencias SQL. Utilizaremos una sintaxis consistente para obtener datos de diversas fuentes de datos, incluyendo datos relacionales, entidades, XML, DataSets de ADO.NET, y colecciones de objetos en memoria. Esta nueva sintaxis embebida en un lenguaje de propósito general adquiere todos sus beneficios: validación de tipos, revisión de errores al momento de la codificación, etc.
Ejemplo de ordenamiento de un vector por el tamaño de sus ítems:
public void OrdernarPalabras()
{
string[] palabras = { "naranja", "manzana", "uva" };
var palabrasOrdenadas =
from p in palabras
orderby p.Length
select p;
Console.WriteLine("La lista ordenada por tamaño:");
foreach (var p in palabrasOrdenadas) {
Console.WriteLine(p);
}
}
Ejemplo de agrupamiento de palabras por sus iniciales:
public void AgrupamientoPalabras()
{
string[] palabras = { "naranja", "manzana", "níspero", "melón", "mandarina", "sandía" };
var palabrasAgrupadas =
from p in palabras
group p by p[0] into g
select new { FirstLetter = g.Key, Palabras = g };
foreach (var g in palabrasAgrupadas) {
Console.WriteLine("Palabras que empiezan con la letra '{0}':", g.FirstLetter);
foreach (var p in g.Palabras) {
Console.WriteLine(p);
}
}
}
LINQ to SQL
LINQ to SQL es la implementación de un mapeador de objetos a modelo relacional ORM (object relational mapping), que está integrado al .NET Framework 3.5. Visual Studio 2008 provee un diseñador gráfico que permite modelar y visualizar una base de datos como un modelo de objetos LINQ to SQL.

Cuando grabemos un diseño realizado en esta herramienta, Visual Studio persistirá las clases que representas las entidades de negocio y la base de datos relacional que hayamos modelado. Además veremos generado una clase que representa el contexto (DataContext). Esta clase es el nexo entre los objetos entidades del negocio y la base de datos, defiendo propiedades para las tablas de la base de datos y métodos para los procedimientos almacenados.
Veamos algunos ejemplos de consumo de datos usando LINQ:
Dim db As New NorthwindDataContext
Dim productos = From p in db.Products _
Where p.Category.CategoryName = "Beverages" _
Select p
Este código muestra cómo recuperar un producto de la base de datos, modificarlo y grabarlo.
Dim db As New NorthwindDataContext
Dim producto = (From p in db.Products _
Where p.ProductName = "Toy 1" _
Select p).Single
producto.UnitsOnOrder = 23
producto.UnitsInStock = 20
db.SubmitChanges()
Tamaño de los Tipos de Datos Definidos por el Usuario basados en CLR
Se ha aumentado la restricción de límite de 8000 bytes a 2 Gb para los tipos de datos definidos por el usuario y agregados basados en CLR (CLR UDT y CLR UDA).
Seguimientos de Cambios
Para poder hacer un seguimiento de los cambios producidos sobre los datos almacenados en SQL Server, anteriormente debíamos agregar una columna datatime o timespan o algún otro mecanismo que hayamos inventado a tal fin. El Seguimiento de Cambio de SQL Server 2008 (SQL Server Change Tracking) está basado en el componente Captura de Cambios de Datos CDC (Change Data Capture), el cual detecta los cambios producidos por insert, update y delete en los datos de forma asincrónica y expone estos datos de forma relacional. Estas tablas generadas por CDC contiene columnas que tiene la misma estructura de las columnas cuyas tablas son monitoreadas, conteniendo a su vez toda la metadata para entender cuál fue el cambio realizado.
HierarchyID
Todos conocemos las limitaciones y dificultados con las que nos topamos al momento de representar y almacenar estructura de datos del tipo jerárquicas: un sinnúmero de joins y lógica compleja.SQL Server 2008 nos da una solución a este problema donde podemos almacenar una estructura jerárquica en el tipo de dato HierarchyID. Este tipo de dato es de longitud variable y se utiliza para localizar la posición donde las relaciones se dan no solo jerárquicamente sino entre elementos del mismo nivel también.
He aquí una lista de los métodos disponibles en el motor de SQL Server 2008 que dan soporte a HiearchyID:
1. GetAncestor, recibe un entero que permite buscar el ancestro n de un nodo hijo.
2. GetDescendant, devuelve un nodo hijo que es descendiente de su padre.
3. GetLevel , indica el nivel del nodo corriente
4. GetRoot , devuelve el nodo raíz del árbol jerárquico
5. IsDescendant, devuelve verdadero o falso dependiendo de si el nodo es un descendiente de su padre
6. Parse, convierte una representación de texto canónica en un HiearchyID
7. Read, interpreta una representación binaria de un HiearchyID
8. Reparent, permite asignar un nuevo padre a un nodo hijo
9. ToString, devuelve una cadena de texto que representa un HierarchyID
10. Write, escribe un HiearchyId en un binario
Datos Espaciales
SQL Server 2008 da soporte para el almacenamiento y tratamiento de datos espaciales. Estos datos permiten almacenar información de localización.
Los modelos espaciales representan puntos, líneas y áreas sobre una superficie. Comúnmente se lo utiliza para representar ubicaciones en el planeta tierra, lo cual son descriptos como Geomática. Geomática es el término científico moderno que hace referencia a un conjunto de ciencias en las cuales se integran los medios para la captura, tratamiento, análisis, interpretación, difusión y almacenamiento de información geográfica. También llamada información espacial o geoespacial.
Modelo Geodésico
La Geodesia es una rama de las Geociencias que trata el levantamiento y la representación de la forma y de la superficie de la tierra, global y parcial, con sus formas naturales y artificiales. Una representación precisa de la tierra es el globo terráqueo, en donde las ubicaciones son manifestadas como latitudes y longitudes. A este modelo se lo conoce como modelo geodésico (Geodetic model) y es la forma más precisa de representar los aspecto geográficos de la tierra, trabajando con una elipsoide y teniendo en cuenta la curvatura de la tierra al momento de calcular distancias.

Modelo plano
Históricamente ha sido mucho más fácil trabajar con modelos bidimensionales, superficies o planos, por lo cual es común encontrarse con información que referencian posiciones geográficas en modelos planos. Para trabajar con información geomática en un modelo plano, hace falta hacer una proyección para aplanar los objetos geográficos del esferoide. Existen varios modelos matemáticos que pueden proyectar el aspecto geográfico de la tierra en un plano, los cuales resultan en una distorsión de la forma y/o superficie y/o posición de los mismos en el plano. Es por eso que los modelos planos son recomendables para porciones geográficas más reducidas como países, estados, ciudades, o terrenos y edificaciones.


Tipos de datos Espaciales
SQL Server 2008 provee el tipo de dato geography para modelos geodésicos y el tipo de dato geometry para modelos planos. Ambos están implementados como tipos del CLR y pueden ser utilizados para almacenar variados tipos de entidades geográficas como ser puntos, líneas y polígonos. Ambos tipos de datos poseen métodos y atributos, que permiten realizar cálculos tales como distancias entre posiciones o encontrar si dos elementos geográficos se intersecan.
El tipo de dato geography almacena una estructura del tipo coordenadas de latitud y longitud. Un caso típico de su uso puede ser el cálculo de las trayectorias de aerotransporte donde la curvatura de la tierra debe tomarse en cuenta.
El tipo de dato geometry almacena una estructura de coordenadas en un modelo plano. Se lo utiliza usualmente en sistemas de mapas regionales o planos de planta donde la curvatura de la tierra es despreciable.