Conectar Visual Basic .NET a SQL Server 2008

Un amigo ha pedido explique como conectar Visual Basic .NET a una base de datos en SQL Server 2008 R2. Veamos como se hace.

Primeramente tenemos que crear un proyecto en Visual Studio (tengo la versión 2008). Por defecto se crea el proyecto con un formulario. Hacemos doble click sobre el formulario para ver el panel del código.

Escribimos la siguiente sentencia arriba de la definición de clase del formulario

Imports System.Data.SqlClient

Quedará como vemos en la imagen:

image

Luego estableceremos la conexión a la base de datos, para eso necesitamos dos datos: el nombre de la instancia del servidor SQL Server y el nombre de la base de datos. Con ellos creamos la cadena de conexión que nos permitirá conectarnos al servidor. Como ven, utilizamos la opción de conexión con seguridad integrada.

image

Luego declaramos el objeto SqlConnection llamado CnxBD , que es el que hace el trabajo de establecer comunicación con el servidor y la base de datos. Y lo único que necesitamos es abrir la conexión con el método Open.

image

Con esa sentencia ya tendremos abierta una conexión a una base de datos de un servidor SQL Server.

Esto es algo básico y como ven no tiene mucha complejidad, posterior a esto, ya podemos ir utilizando otros objetos como SqlCommand, Dataset, etc.

Descargar código del ejemplo.

Si tienes alguna duda o consulta, deja tu comentario.

Pantalla de Bienvenida con Windows Forms

En este artículo veremos como implementar una pantalla de bienvenida (splash screen) para nuestra aplicación. Lo haremos en Windows Forms (Visual Basic .NET 2008 / .NET Framework 3.5).

Seguramente muchas veces has visto que las aplicaciones muestran una pantalla de bienvenida antes de mostrar la pantalla real.

Aquí utilizaremos varias imágenes en una especie de carrusel, es decir una serie de imágenes apareciendo una tras otra en la pantalla de bienvenida automáticamente.

Para empezar hay que crear una aplicación Windows Forms llamada PantallaSplash.

Al formulario que se agrega automáticamente, hay que incorporar tres componentes: un ImageList (con el nombre imgPics), un Timer (tmrSplash) y un PictureBox (picBox) de la caja de herramientas.

En el control ImageList imgPics almacenaremos una o más imágenes. La configuración debe estar como la siguiente.

image

Con el control Timer controlaremos un intervalo de tiempo en que un evento se ejecute. Configura el timer como se ve en la siguiente imagen.

image

Y en el control PictureBox mostraremos una imagen. Configúralo de la siguiente manera (tienes que establecer una de las imágenes que pusimos en el control ImageList):

image

Asegúrate que el tamaño del control PictureBox tenga el mismo tamaño que se coloco en la propiedad ImageSize del control ImageList.

Escribamos el siguiente código que es el que hará el trabajo.

image

En el evento Load del formulario habilitamos el timer. Con la variable “index” vamos recorriendo la lista de imágenes y mostrándolas en el control PictureBox.

A continuación dejo el enlace para que puedan descargar el código (incluyo las imágenes que utilicé).

PantallaBienvenida.zip

Como Reducir el Tamaño del Log de Transacciones en SQL Server

Una pregunta muy común es cómo reducir el tamaño del log de transacciones en SQL Server 2008 o en versiones superiores, porque son instrucciones diferentes que las utilizadas para SQL Server 2000 o SQL Server 2005 .

Reducir el Log de Transacciones en SQL Server 2008

En este caso usaremos la base de datos AdventureWorks:

USE AdventureWorks

GO

ALTER DATABASE AdventureWorks

SET RECOVERY SIMPLE

GO

DBCC SHRINKFILE (AdventureWorks_Log)

GO

ALTER DATABASE AdventureWorks

SET RECOVERY FULL

GO

Recuerda que en este ejemplo la instrucción DBCC SHRINKFILE reduce el fichero de log al máximo (en el parámetro se le debe indicar el nombre lógico del fichero).

Reducir el Log de Transacciones en SQL Server 2000/2005

Primero ejecuta el siguiente código:

DBCC SHRINKFILE(pubs_log, 2)



Si no se obtiene el tamaño deseado, ejecute lo siguiente:





BACKUP LOG pubs WITH TRUNCATE_ONLY



Eso trunca el registro, sin posibilidad a una copia de seguridad.




10 Ideas Asesinas en el Desarrollo de Software

Los ingeniero de software son siempre curiosos, entusiastas y animados a hacer todas las cosas. Al menos al principio. En el camino, estos cabezotas se enfrentan con un mundo que definitivamente no entiende sobre el desarrollo de software, sistemas que cuentan ingenieros por números, productividad por líneas de código y calidad de procesos; un mundo donde el desarrollo de software está manejado por una burocracia que maneja riesgos más que un consejo creativo que pueda resolver los problemas de los clientes.

Desafortunadamente, muchos ingenieros consideran esto una llamada para despertar y adoptar esas formas burocráticas, convencidos que han aterrizado en un nuevo y adulto mundo de la administración. Alguien que administre resistir a dar un mal paso y no caiga en las tentaciones del martirio, ya que cada fallo es algo que la administración hizo o no hizo.

Si eres un ingeniero de software o un jefe de ingenieros, a continuación tenemos una lista para ayudarte a identificar si sigues con tus genes de desarrollo de software activos o te has convertido en alguien que dicta clichés de forma robótica en cada reunión, asesinando cada idea y la moral detrás de ella:

10. "Esto es suficientemente bueno" : El hecho es que nada es suficientemente bueno, al menos para cualquier software. Puede ser suficientemente bueno para hoy, o para esta versión, pero si tu producto ha tenido el mismo problema la última década, alguna empresa de la competencia ya se ha llevado a tus clientes por ello. Repáralo antes que llegues al punto donde no puedas.

9. "Esta es la forma en que siempre lo hemos hecho": Esto es un anacronismo en cualquier campo competitivo y rápidamente cambiante. Especialmente en el software. Las empresas de software no son como empresas fabricantes de autos que pueden ensamblar cualquier línea y olvidarse de ella por unos cien años. ¡Espera un minuto! Ni siquiera las empresas fabricantes de autos hacen eso. Los problemas de hoy requieren un nuevo conjunto de soluciones porque en una industria que funciona bajo algo como las Leyes de Moore, junto con las expectativas de las personas, hay un estado permanente de cambio.

8. "Hay suficiente tiempo para hacerlo bien": Esto es la forma en que acabas en deuda técnica. De alguna forma es inevitable debido a las presiones del negocio o trabajar con una nueva pieza de hardware o tecnología. Tanto como vas pagando tu deuda en el futuro inmediato, esto es parte del proceso, pero si evitas hacer las decisiones correctas y la responsabilidad va con eso, no vas a ser consecuente con tus principios de ingeniero de software.

7. "Esto requiere cambios arquitecturales profundos": ¿Qué cosa no las necesita? Idealmente, una pieza bien diseñada de software debería ser flexible a los cambios mientras el producto se va desarrollando. Pero como nosotros dijimos, la demanda en el software cambia rápidamente y cada pieza de software escrita necesita ser volver a ser escrita. Esta es la naturaleza del trabajo, no una anomalía para ser utilizada como una excusa.

6. "La Administración no lo ha priorizado": ¿Acaso la administración no ha priorizado hacer un buen producto? ¿libre de errores? ¿sin código mal escrito? ¿que hace al cliente feliz? De acuerdo, algunas veces heredamos código y tendremos que lidiar entre reparar lo que ya está hecho y escribir nuevo código pero ese es un argumento poco válido como veremos a continuación. Es suficiente decir que la ingeniería necesita configurar y ejecutar sus propias prioridades, aunque sean pequeñas, cada día, en vez de esperar por algún mandato superior y mágico, ya que eso no va a suceder.

5. "Hay mucho en nuestro plato": Esta es una de las tautologías sin sentido que no añade nada a la discusión. El foco no es más la idea o como debería ser ejecutada sino “no tenemos recursos” o la enorme lista de errores presentada por el cliente. Por supuesto que tienes mucho en tu plato, ya que te pagan por tener eso en tu plato, empieza a comer.

Si una idea vale ser ejecutada, su adopción no debería depender si tienes o no mucho en tu plato, si llenas tu plato en el buffet con basura y decides que no tienes el plato deseado porque tu plato está lleno, ya has hecho dos cosas mal: elegiste malas cosas para empezar y no tienes que hacer muchos cálculos para saber que tienes que tirar la basura y conseguir lo que quieres. No mates la idea, limpia el plato.

4. "Nuestro software es muy completo, tenemos que tener cuidado si hacemos cambios": Esta es otra tautología sin sentido. ¿Qué software empresarial no es complejo? ¿Estás diciendo que no eres usualmente poco cuidadoso cuando escribes código? Eres un ingeniero de software, y debes esperar lidiar con la complejidad y ser cuidadoso cuando haces cambios, es un requerimiento básico. Si esta fuera una razón por la que los ingenieros no pueden ejecutar una idea, deberíamos aprender nuevamente lo básico.

3. "Nadie está pidiendo eso": Esto puede hacer recordar a un comentario que hizo Henry Ford: “si le preguntara a la gente, lo que ellos quieren, ellos dirán que quieren un caballo más rápido”. Los seres humanos son increíblemente adaptables, ellos vivirían con cualquier cosa, incluyendo como dijo Ford, caballos más rápidos. Si le das a tus clientes un producto por debajo de los estándares, ellos vivirán con eso. Pero recuerda que los humanos también somos increíblemente cambiantes, una idea que mates o que tengas encerrada, crecerá en otra empresa. Si somos descuidados porque creemos que nuestro software es “pegajoso” (es decir que los clientes nos odian pero no pueden cambiar porque es mucho trabajo), estamos fijando nuestro techo en un nivel que no vale para un verdadero ingeniero.

2. "Tenemos consensos": Esto parecería una afirmación inocua con noble intención, pero es insidiosa y fijándonos bien, no tienen ningún significado en el contexto del software. El consenso tiene una indebida importancia en todo desde reuniones de diseño, revisiones de SRS/SDS, documentación, prácticas de QA, etc. El desarrollo de software es un ejercicio de conducción por expertos. Alguien que ha pasado años estudiando, aprendiendo y trabajando en un campo específico, y no apartas a esa persona para la decisión final arrojando toda esa experiencia, sin mencionar que puedes entregar un mal producto, desmoralizar al experto, y adoptar la forma más segura y más tímida y más insidiosa de todas, la contabilidad difusa.

Una decisión de grupo es una forma de evadir la responsabilidad por el producto. “Lo decidimos todos”, es una forma de decir: “nadie es responsable”. En un sistema presidencial de gobierno, el congreso recomienda al presidente pero el presidente es el que toma la decisión. A menos que la decisión del presidente sean obviamente horrenda que la mayoría del congreso decida vetar la decisión, esta queda.

1. "No puede ser hecho": No hay nada que no pueda ser hecho en software. Los chicos no ingenieros te rodean diciendo “es solo software, cierto” como una forma gentil de provocar a los ingenieros ¡pero es verdad! Es esencialmente solo software. Los ingenieros debería responder especificando lo que toma implementar más que decir que no puede ser hecho. Deberíamos decir “tomará 3 ingenieros, con licencias para XYZ, cinco computadoras con el procesador DFE, con 2 TB de almacenamiento, y 8 meses para hacer ese software”, en vez de “no puede hacerse”.

Todo puede ser hecho, fijemos eso en nuestra mente primero. El resto caerá por su propio peso.

Información de Tablas [Script SQL]

Este script puede ser utilizado para obtener la información de tablas.

SELECT TAB.NAME AS NOMBRE_TABLA, COL.NAME AS NOMBRE_COLUMNA, TIP.NAME AS TIPO_DATO, COL.MAX_LENGTH AS TAMAO,

CASE
    WHEN COL.IS_NULLABLE = '0' THEN 'NO'

    ELSE 'SI'

END AS ACEPTA_NULL,

EXT.VALUE AS DESCRIPCION
    
FROM SYS.TABLES TAB

INNER JOIN

SYS.COLUMNS COL ON TAB.OBJECT_ID = COL.OBJECT_ID

INNER JOIN

SYS.TYPES TIP ON TIP.USER_TYPE_ID = COL.USER_TYPE_ID

LEFT OUTER JOIN

SYS.EXTENDED_PROPERTIES EXT ON EXT.MAJOR_ID = TAB.OBJECT_ID AND COL.COLUMN_ID = EXT.MINOR_ID

Reemplazando Cursores con Consultas SQL

Para poner las cosas en claro, creo que así como yo, casi todos prefieren evitar los cursores en la mayoría de los casos. ¿Son necesariamente malos? ¿Es una regla absoluta el evitar a un cursor? No. Algunas veces la operación que se necesita no puede ser hecha en base a conjuntos de datos, y un cursor puede ser desarrollado más rápido que un programa. Algunas veces es conocido que el avance en el bucle sólo involucra cientos de registros y no tomará mucho tiempo ejecutarse. Algunas veces estás trabajando con cursores ya existentes y sólo necesitas unos cambios menores, modificando el cursor en este escenario será más rápido que reescribir el procedimiento desde cero. Pero en general, yo intento evitar cursores mientras sea posible, y siempre busco alternativas para codificar la lógica.

Es posible remover a esos feos cursores de la lógica de datos, en algunos casos es más complicado. Vamos a ver un ejemplo de un cursor que tal vez deberíamos reemplazar. Por ejemplo un cursor utilizado para extraer información de estudiantes y que actualice la elección de transporte, un estudiante a la vez. La lógica es la siguiente:

1. Recuperar el nivel de grado del estudiante (inicial, primaria, o secundaria) en una variable.

2. Limpiar el código de transporte si el estudiante está dentro de la distancia adecuada para caminar a la escuela (la distancia es determinada en base también al nivel del estudiante).

3. Si el estudiante no está en una categoría particular (educación especial por ejemplo) y no está en un conjunto particular de colegios, establece el código de transporte a inelegible si los estudiantes están fuera de la zona.

4. Si el estudiante está en un programa de mediodía, actualizar el código de transporte para resaltar el hecho que el transporte será por mediodía.

5. Actualizar el código de transporte si el estudiante no reúne ninguno de los otros criterios.

La lógica utilizada en el cursor sería una enredada telaraña de sentencias de actualización, anidadas en una lógica muy compleja. Para hacerlo peor, digamos que hay 60 mil estudiantes, y esto podría tomar algo de 20 minutos para ejecutarse.

El Cursor

Veamos ahora como podría ser el cursor a utilizar para la operación que explicamos anteriormente.







 
DECLARE  EstudiantesCursor   CURSOR FAST_FORWARD FOR
SELECT
NumeroEstudiante,
CodigoEscuela,
CodigoTransporte,
NivelGrado,
CodigoGeografico,
ZonaHogar,
CodigoBilingual,
CodigoSped
FROM
-- [Tablas para obtener la información de estudiantes]   OPEN EstudiantesCursor   FETCH NEXT FROM EstudiantesCursor INTO
@
NumeroEstudiante,
@
CodigoEscuela,
@
CodigoTransporte,
@
NivelGrado,
@
CodigoGeografico,
@
ZonaHogar,
@
CodigoBilingual,
@
CodigoSped


WHILE @@FETCH_STATUS = 0
BEGIN
-- Para el nivel de grado, ver si el estudiante es inelegible


              -- para transporte (vive muy cerca de la escuela).
IF EXISTS(SELECT Sch FROM DistanciaCaminando
WHERE CodigoEsc = @CodigoEscuela
AND CodigoGeo = @CodigoGeografico


                           AND NivelGrado = @NivelGrado)
BEGIN
UPDATE
Registro
SET
CodigoTransporte = '',
LastUpdateUserID= 'CScrpW' -- inelegible
WHERE
NumeroEstudiante = @
NumeroEstudiante



AND CodigoEsc = @CodigoEscuela  GOTO FetchNext
END     IF ((rtrim(@CodigoBilingual) = ''
OR RTRIM(isnull(@
CodigoBilingual,'')) = 'S')
AND (@CodigoSped = ''
OR SUBSTRING(@CodigoSped, 1, 1) IN ('S', 'R')
OR @CodigoSped IN ('V1', 'V2', 'P1', 'P2')))
BEGIN
IF @NivelGrado <> 'H'
AND NOT EXISTS
(SELECT Escuela FROM BufferZoneLookup
WHERE Escuela = @Escuela
AND
NivelGrado = @NivelGrado
AND (CodigoGeo = @CodigoGeografico
OR ZonaHogar IN (@ZonaHogar, 'C','H')))
BEGIN
-- codigo aqui para ejecutar una actualizacion pero


--indicando el codigo de transporte a 'C0RR' y el UltimoUsuario a 'CScrpZ'
END   GOTO FetchNext
END   -- Dos actualizaciones adicionales con condicionales



FetchNext:
FETCH NEXT FROM EstudiantesCursorINTO
@NumeroEstudiante,
@
CodigoEscuela,
@
CodigoTransporte,
@
NivelGrado,
@
CodigoGeografico,
@
ZonaHogar,
@
CodigoBilingual,
@
CodigoSped


	END
END
CLOSE EstudiantesCursor
DEALLOCATE EstudiantesCursor



Lo siguiente que hay que hacer para reemplazar el cursor con una sentencia SQL de conjuntos de datos es identificar las condiciones y bucles a repetir.



1. Encapsular las condiciones if/else que hay en el cursor en una tabla temporal con múltiples columnas tipo BIT. Para estas, mas de una de las condiciones pueden ser establecidas.



2. Utilizar la tabla temporal con las configuraciones tipo bit para determinar el código de transporte. Las sentencias de actualización simplemente modifican el código de transporte ý la última actualización al usuario, de modo que eso se realiza en una tabla temporal secundaria. En la lógica, el orden de las sentencias case realiza las actualizaciones en el cursor.



3. Utilizar los códigos de transporte que tenemos en la tabla 2 para realmente hacer las actualizaciones.



A continuación el SQL resultante:















 

-- Esta consulta llenará una tabla con diferentes campos tipo bit 
-- representando las condiciones if/else utilizadas en el cursor.
-- de modo que esto esencialmente centraliza las condiciones if/else en un
-- registro por cada estudiante que pueda ser usada para la siguiente consulta.
SELECT
ds.NumeroEstudiante,
ds.CodigoEscuel,
ds.CodiogTransporte,
ds.NivelGrado,
ds.CodigoBilingual,
ds.CodigoSped,
ds.CodigoGeografico,
ds.ZonaHogar,
(CASE WHEN ds.sch IN('4261','1010','1020','1340')
THEN 1 ELSE 0 END) AS 'NoPuedeEstarFueraDeZona',


– distancia ciudad
(CASE WHEN isnull(ZonaEsc.esc, '') <> '' THEN 1 ELSE 0 END)
AS 'EnZonaOZonaBuffer',
(CASE WHEN isnull(DistanciaCaminando.es, '') <> '' THEN 1 ELSE 0 END)
AS 'EstaEnLaDistanciaCamino',
(CASE WHEN ds.grado IN ('K0', 'K1')
AND ds.esdiaextendido = 0 THEN 1 ELSE 0 END)
AS 'InicialMedioDia',
-- Bilingual estudiantes de otro idioma que siempre necesitan transporte.
(CASE WHEN NOT isnull(ds.CodigoBilingual, '') = ''
AND NOT (isnull(ds.CodigoBilingual,'')) = 'S' THEN 1 ELSE 0 END)
AS 'BilingualInelegibleParaC0RR',
-- casos adicionales omitidos


 [SpedInelegibleParaC0RR]
INTO #EstudiantesProcesar


FROM


—[lista de tablas] similar a las que están en la definición del cursor


—usa los campos tipo bit para indicar el tipo de codigo de transporte


SELECT  ds.numeroEstudiante, ds.codigoTransporte AS 'curTransCodigo',
-- en el rango idnicado
(CASE WHEN
EstaEnLaDistanciaCamino= 1 THEN ''
-- indica fuera de zona, secundaria y otras categorias no pueden estar


--fuera de zona


	WHEN BilingualInelegibleForC0RR = 0
AND NOT sys.grado IN('09','10','11','12')
AND EnZonaOZonaBuffer = 0
AND NoPuedeEstarFueraZona = 0 THEN 'C0RR'
WHEN (EsInicialMedioDia = 1
AND isnull(sys.transcode, '') = '') THEN 'C5*R'
WHEN (EsInicialMedioDia = 1
AND isnull(sys.codigotransporte, '') <> '') THEN sys.codigotransporte
ELSE 'C5RR' END) AS 'CodigoPropuestoTransporte'
INTO #CambiosTransportecodigoPropuesto
FROM
-- [lista de tablas] 


--ejecuta la actualizacion, indica los codigos de elegibilidad de transporte 


--[c5rr, c0rr, etc].  
-- cada actualización usa un ID diferente
UPDATE ds SET codigotransporte =
CodigoPropuestoTransporte,
ultimoUsuario = (CASE isnull(CodigoPropuestoTransporte, '')
WHEN 'c5rr' THEN 'CScrpC'
WHEN 'c0rr' THEN 'CScrpZ'
WHEN '' THEN 'CScrpW'
WHEN 'C5*R' THEN 'CScrpK'
ELSE 'CScrpX' END)
FROM
-- [lista de tablas]

 


Esta consulta se ejecutará 10 o 100 veces más rápido que el cursor. ¿Porqué es tan lento el cursor? Porque cada estudiante es procesado uno a la vez. Y para empeorar las cosas, dentro de cada bucle del cursor, hay algo de cinco consultas a la vez, lo que si contamos con 60 mil estudiantes, serían algo de 300 mil consultas. Y sólo se necesitaban 3. Pero, y siempre hay un pero en la vida, la opción de usar un cursor mejora la depuración y lo hace más flexible que la opción de consultas. Siempre hay que decidir que es lo que queremos obtener: velocidad o simplicidad.

¿Dónde Poner la Lógica? ¿En SQL o en el código?

SQL es un poderoso lenguaje de programación y es muy bueno para lo que fue hecho, consultas de conjuntos de datos. C#, Java y otros lenguajes son también poderosos, más poderosos que SQL en muchas formas. Para bucles y tareas en forma de procedimientos, C# puede procesar cientos de registros muchas veces más rápido que un cursor SQL, e incluso hacerlo en unas líneas de código más escasas. SQL simplemente no fue hecho para hacer ese tipo de procesamiento. En vez de eso, SQL fue hecho para procesar conjuntos de datos donde las tablas y conjuntos de resultados son utilizados y combinados en base a condiciones.

De manera similar, SQL es de lejos la interfaz de usuario que uno quiere tener. Muchas tareas que necesitan una interfaz de usuario, no son apropiadas para la lógica SQL. Por ejemplo, si los nombres de clientes deberían aparecer en una rejilla web con el formato [nombres],[apellido paterno][apellido materno], una opción es retornar los datos desde una sentencia SQL con ese formato. Sin embargo, un método más apropiado es simplemente retornar las partes del nombre, y que la lógica en la interfaz de usuario formatee el nombre completo en el formato deseado.

Algunos puntos para tomar en cuenta:

1. ¿Qué pasa si la capa de negocios o la interfaz de usuario está bloqueada y la única forma de cambiar el formato es cambiar los datos que se carga?

2. ¿Qué pasa si en vez de que los datos sean llamados por una aplicación o sólo un sitio web, sean llamados por 2 o 3 aplicaciones web, y estén disponibles como un servicio web, y de paso por una aplicación de consola? Mientras que en teoría un componente de negocios puede ser desarrollado para manejar todas esas llamadas, una opción más fácil es simplemente centralizar a nivel de base de datos en un procedimiento almacenado la salida de datos.

3. ¿Qué pasa si los resultados necesitan ser llamados por otra pieza de lógica SQL? Podría ser transformados en una vista.

4. ¿Qué pasaría si el resultado está destinado a mostrarse como un archivo de Excel que será rápidamente modificado ya que el usuario pide un reporte personalizado? ¿Qué pasa si ellos solicitan otra vez una pequeña modificación de la lógica unos cuantos minutos después que finalices de modificar el formato del archivo de Excel? ¿No podría ser más fácil tener la lógica en el SQL en este caso?

5. ¿Qué sucede si el desarrollador que escribió la lógica es simplemente más adepto a una solución basada en SQL para lo que se necesita?

Para mi, si algo puede ser hecho en forma de conjuntos de datos, trato de hacerlo en SQL para terminar el trabajo, en todo lo que sea posible que pueda ser hecho en forma de conjuntos de datos, vayamos a la lógica SQL (y todo lo que requiera lógica de procedimientos va en el código).

¿Que dices tú?