martes, 8 de abril de 2008

[DSL] Agregar un menú personalizado en VS2008

La forma en la que se añade un menú personalizado ha variado en la nueva versión de Visual Studio 2008. El SDK de extensibilidad de Visual Studio 2008 ha variado la forma en la que se generan menús y comandos de forma que ya no se utilizan los “antiguos” ficheros de configuración .ctc.

Como pequeña introducción, os digo que en la nueva versión se ha optado por un nuevo sistema de configuración más acorde a los tiempos que corren basado en XML. Dicho sistema de configuración está completa y exquisitamente explicado en el siguiente enlace (no apto para lectura al final del dia;).

Dicho esto, os aviso de antemano que la documentación que viene con la propia descarga del ejecutable SDK Extensibility 1.0 para Visual Studio 2008 es errónea y hace referencia al antiguo sistema de configuración (por lo menos en lo que nos atañe que son los menús en DSL). El antiguo sistema de agregación de menús personalizados en nuestros lenguajes de dominio está explicado bastante bien en el blog de “El Bruno” o en la propia documentación que viene con el descargable de extensibilidad que he mencionado.

Vamos a ponernos manos a la obra. Para ello parto de que tienes ya tu proyecto de lenguaje de especificación de dominio creado…

image

Tal cual está, podemos crear nuestro menú de una forma bastante más sencilla que antes siguiendo los siguientes pasos:

1. En el “Solution Explorer”, desplegar el proyecto DslPackage y editar el archivo Commands.vsct

image

En dicho archivo es donde vamos a tener que añadir los elementos del menú que queremos. En nuestro caso vamos a crearnos un botoncito que nos diga la figura que hemos clickeado.

La forma de crear nodos dentro del archivo está “explicada” muy por encima en los documentos de ayuda de mdsn (por lo menos ahora cuando escribo este post) por lo que seguramente acabarás antes viéndolo desde aquí ;)

Básicamente lo que vamos a hacer es definirnos un botón y una identificación del mismo. Importante a tener en cuenta son los nodos <Commands/> y <Symbols/> (no quiero liaros con el nodo <Extern/> que no vamos a tocar ahora)

2. Dentro del nodo <Commands/> introducir un nodo con la descripción del botón que quereis crear

<Buttons>
<Button guid="cmdDimeNombreFiguraGUID" id="cmdDimeNombreFiguraID type="Button">
<Parent guid="guidCmdSet" id="grpidContextMain"/>
<Strings>
<CanonicalName>cmdDimeNombreFigura</CanonicalName>
<ButtonText>Nombre figura</ButtonText>
<ToolTipText>Dice el nombre de la figura seleccionadaToolTipText>
</Strings>
</Button>
</Buttons>

3. Fuera del nodo <Commands/> y al mismo nivel que él, declaramos el nodo <Symbols/> de la siguiente forma

<Symbols>
<GuidSymbol name="cmdDimeNombreFiguraGUID" value="{D5A40ECA-BA87-4a92-B6A7-A36C27C858AE}">
<IDSymbol name="cmdDimeNombreFiguraID" value="1"/>
</GuidSymbol>
</Symbols>

El valor del GuidSymbol ha sido generado mediante la aplicación guidgen.exe
El valor del IDSymbol puede ser decimal o hexadecimal (por ejemplo, valores 0x104 pueden darse) y podemos darle el que queramos.

4. Estado del fichero Commands.vsct

Una vez realizado esto, el fichero queda de la siguiente manera:

<?xml version="1.0" encoding="utf-8"?>
<CommandTable xmlns="http://schemas.microsoft.com/VisualStudio/2005-10-18/CommandTable xmlns:xs="http://www.w3.org/2001/XMLSchema>
<!-- -->
<!-- This file contains custom command definitions. -->
<!-- -->
<!-- NOTE: Each time commands are added or changed, the "version" parameter to the -->
<!-- ProvideMenuResource attribute in Shell\Package.tt should be incremented. -->
<!-- This causes Visual Studio to re-merge the menu definitions for the package. -->
<!-- Otherwise, changes won't take effect until the next time devenv /setup is run. -->
<!-- -->
<Extern href="stdidcmd.h"/>
<Extern href="vsshlids.h"/>
<Extern href="msobtnid.h"/>
<Extern href="virtkeys.h"/>
<Extern href="DSLToolsCmdID.h"/>
<Include href="GeneratedCode\GeneratedVsct.vsct"/>
<Commands package="guidPkg">
<Buttons>
<Button guid="cmdDimeNombreFiguraGUID" id="cmdDimeNombreFiguraID" type="Button">
<Parent guid="guidCmdSet" id="grpidContextMain"/>
<Strings>
<CanonicalName>cmdDimeNombreFigura</CanonicalName>
<ButtonText>Nombre figura</ButtonText>
<ToolTipText>Dice el nombre de la figura seleccionada</ToolTipText>
</Strings>
</Button>
</Buttons>
</Commands>
<Symbols>
<GuidSymbol name="cmdDimeNombreFiguraGUID" value="{D5A40ECA-BA87-4a92-B6A7-A36C27C858AE}">
<IDSymbol name="cmdDimeNombreFiguraID" value="1"/>
</GuidSymbol>
</Symbols>
</CommandTable>

5. Ahora, siguiendo lo que dice en los comentarios del propio fichero a la parte de arriba, le incrementamos el nº de versión al atributo ProvideMenuResource del fichero “GeneratedCode/Package.tt” (notese que en el comentario referencia a Shell/Package.tt ;)

image

Para ello, lo editamos y reemplazamos lo que viene por defecto ( [VSShell::ProvideMenuResource("1000.ctmenu", 1)] ) , por [VSShell::ProvideMenuResource("1000.ctmenu", 2)]

6. Ahora, vamos a asignarle el comportamiento al botón. Para ello hemos de abrir el fichero GeneratedCode/CommandSet.cs

image

Y le añadimos los métodos OnPopUpMenuClick(), OnPopUpMenuDisplayAction() y GetMenuComands() a la clase.

Evidentemente lo que no vamos a hacer es escribir el código directamente sobre el fichero CommandSet.cs puesto que dicho fichero se machaca cuando le damos a “Transform All Templates” por lo que haciendo uso de las posibilidades de definición de clases parciales, le definiremos el código en un nuevo fichero.

7. Creamos la carpeta Customization y luego añadimos una nueva clase, que será la que contenga el código, de forma que nos quedará como la figura siguiente:

image

NOTA: En mi caso, mi lenguaje se llama LenguajeOOMM y por eso la clase generada en CommandSet.cs se llama así. Por seguir una nomenclatura estándar he creado dicho nombre al fichero. En cualquier caso, el contenido siempre ha de ser el de la definición de la clase doblemente derivada.

Antes hacíamos referencia al fichero CommandSet.cs. Por poco que lo abramos y le demos un vistazo veremos que sigue la pauta de clase doblemente derivada (que se sale del tema del post pero que en futuros post trataré) que crea una clase heredada de DslShell::CommandSet (en mi caso llamada LenguajeOOMMCommandSetBase), y luego otra clase que hereda de la anterior y es a la que vamos a añadirle la funcionalidad citada en el paso 6.

8. Introducimos el siguiente código dentro de LenguajeOOMMCommandSet.cs (en tu caso, el fichero .cs que has creado para tal fin)

using System;
using System.Collections.Generic;
using System.ComponentModel.Design;
using Microsoft.VisualStudio.Modeling.Shell;
using System.Collections;
using System.Text;

namespace LenguajeOOMM
{
/// <summary>
/// Double-derived class to allow easier code customization.
/// </summary>
internal partial class LenguajeOOMMCommandSet : LenguajeOOMMCommandSetBase
{
protected override IList<System.ComponentModel.Design.MenuCommand> GetMenuCommands()
{
IList<System.ComponentModel.Design.MenuCommand> commands = base.GetMenuCommands();

DynamicStatusMenuCommand cmdDimeNombreFigura =
new DynamicStatusMenuCommand(
new EventHandler(OnPopUpMenuDisplayAction),
new EventHandler(OnPopUpMenuClick),
new CommandID(new Guid(“D5A40ECA-BA87-4a92-B6A7-A36C27C858AE”), 1));

commands.Add(cmdDimeNombreFigura);

return commands;
}

/// <summary>
/// Lo que se desencadena al pinchar sobre el boton.
/// En principio no queremos nada mas que se muestren los objetos seleccioonados
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
internal void OnPopUpMenuClick(object sender, EventArgs e)
{
MenuCommand command = sender as MenuCommand;

StringBuilder sb = new StringBuilder();
foreach (object selectedObject in this.CurrentSelection)
{
sb.AppendLine("Objetos Seleccionados: " + selectedObject.ToString());
}

System.Windows.Forms.MessageBox.Show(sb.ToString());
}

/// <summary>
/// Se desencadena cuando vamos a mostrar el menú.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
internal void OnPopUpMenuDisplayAction(object sender, EventArgs e)
{
MenuCommand command = sender as MenuCommand;

foreach (object selectedObject in this.CurrentSelection)
{
// Solo se desencadena si entre todos los objetos seleccionados, hay algun ExampleShape
//para conectores por tanto no sale. Comportamiento a posta
if (selectedObject is ExampleShape)
{
command.Visible = true;
command.Enabled = true;
return;
}
}
//por defecto deshabilitado
command.Visible = false;
command.Enabled = false;
}
}
}

9. Una vez llegados a este punto solo nos queda pinchar sobre “Transforma ll templates” y compilar.
Ahora nos saldrá el elemento del menú en cuestión y al clickear nos saldrá un MessageBox con la información que queríamos.

image

image

Ni que decir tiene las posibilidades de esto. Podemos crearnos un menú que interactúe con nuestro propio modelo de forma que podamos cambiar incluso el aspecto o propiedades de nuestros objetos para que sin tener que borrar figuras, las podamos modificar

martes, 25 de marzo de 2008

Diapositivas de SQL Server 2008 Jumpstart

En los meses de Febrero y Marzo llevamos a cabo en la sede de Microsoft Ibérica la presentación de SQL Server 2008 de una forma un poco más técnica. Esta presentación recibió el nombre de SQL Server 2008 Jumpstart y en ella, durante dos días estuvimos enseñando a los asistentes la mayoría de las novedades que se nos vienen encima con SQL Server 2008 tanto a nivel relacional como a nivel de inteligencia de negocio.

Hemos puesto a descarga libre para cualquiera que lo desee, las diapositivas de lo que enseñamos, simplemente descargándolo de aquí:

En las diapositivas, podrás ver que se mencionan demostraciones de las características (no va a ser todo teoría, claro ;). Recuerda que al igual que acabamos de hacer con las diapositivas, hace pocos días también publicamos los vídeos de las demostraciones que acompañaban a las mismas. Simplemente te remito al post donde se liberaron: http://blogs.solidq.com/ES/ElRinconDelDBA/Lists/Posts/Post.aspx?ID=50

Si deseas conocer las novedades relativas a Inteligencia de negocio, pásate por aquí al lado en el blog de nuestro equipo de inteligencia de negocio, donde se publicaran los materiales de BI: http://blogs.solidq.com/ES/BICorner/default.aspx

domingo, 23 de marzo de 2008

Change Data Capture y el modo de recuperación BULK LOGGED

En SQL Server 2008 aparecen entre otras muchas novedades, la posibilidad de realizar monitorización de cambios de datos en tablas (a nivel de columnas si queremos). Esta tecnología se denomina Change Data Capture (sus siglas CDC) y viene a mejorar y facilitar las labores relacionadas con la LOPD, ya que nos permite de una forma cómoda y sencilla realizar un seguimiento de cambios de nuestros datos de forma automática.

Hasta la llegada de SQL Server 2008, solo teníamos la opción de realizar esto de forma manual de la siguiente manera:

  • Crear una tabla con el mismo esquema que la tabla a auditar (mismas columnas y mismos tipos de datos).
  • Crear Triggers para inserción, modificación y borrado sobre la tabla a auditar, que se encargarían de replicar los cambios sobre la tabla LOPD.

Este proceso, aparte de ser obviamente costoso puesto que requería de un proceso de codificación y mantenimiento elevado (alguien lo tenía que acabar programando), tenía un gran impacto en el rendimiento de la BBDD puesto que implicaba que cada modificación de datos desencadenaría un trigger y un INSERT en alguna tabla.

Para solucionar esta problemática aparece entonces CDC en SQL Server 2008 ya que minimiza el impacto en el sistema utilizando la infraestructura del agente de lectura del log de transacciones existente de forma que los cambios auditados aparecen de forma asíncrona en las tablas de auditoría.


El título de este post es referente a una de las preguntas que se nos realizó durante el evento de SQL Server 2008 Jumpstart en Microsoft Ibérica hace unos días. Uno de los asistentes planteó la duda de si esta infraestructura funcionaría cuando estábamos utilizando un modo de recuperación BULK LOGGED. En ese momento no pudimos responder mediante un ejemplo práctico puesto que teníamos un tiempo limitado para realizar las demostraciones, pero algún asistente comentó la posibilidad de que no funcionaria en ese escenario ya que al fin y al cabo lo que se hace es leer del log de transacciones y "en una etapa BULK LOGGED lo que se realiza mediante carga masiva no queda registrado en el log de transacciones".

Por un lado hemos de apuntar que el comportamiento de modificaciones INSERT, UPDATE y DELETE evidentemente funcionara en cualquier tipo de configuración de modo de recuperación (FULL, SIMPLE o BULK LOGGED), puesto que en todos los modos se escribe todo absolutamente en el log de transacciones (otra cosa es que se hace con esos datos escritos). La duda estaba en el modo de recuperación BULK LOGGED ante cargas masivas (BULK INSERT) puesto que en la demo se mostró el funcionamiento de CDC en un entorno configurado con modo de recuperación SIMPLE.

Antes de nada, voy a explicar cómo nos podemos beneficiar del modo de recuperación BULK-LOGGED.

Como alguien comentó, el modo de recuperación BULK-LOGGED no registra en el log de transacciones las modificaciones realizadas mediante una carga masiva…pero esto no es del todo cierto siempre, puesto que solo ocurre en determinadas condiciones.

Las condiciones que han de cumplirse para logging mínimo son:

  • La base de datos ha de estar obviamente con modo de recuperación BULK-LOGGED
  • La tabla que va a sufrir la actualización masiva no ha de estar replicada
  • Se utiliza TABLOCK (bloqueo de tabla) en la actualización masiva
  • La tabla destino ha de cumplir con los requisitos de datos e indexación de la tabla siguiente:

    Clustered Index

    Nonclustered Index

    Si

    No

    Si

    No

    TABLA

    Vacía

    Minimo

    Minimo

    Minimo

    Minimo

    Con Datos

    Completo

    Minimo

    Index

    Minimo


Dicho esto, os comento ahora que internamente CDC utiliza un "log reader agent" , al igual que sucede en replicación transaccional. Dicho de otro modo…que aunque en los Books Online no diga nada al respecto porque todavía no están completos (cuando escribo esto estamos en CTP6 todavía), seguro que aparece un punto más, diciendo que la tabla que va a sufrir la modificación masiva, no puede estar siendo auditada mediante CDC para poder tener logging mínimo ante modificaciones masivas ;)

Dicho esto, me monté el entorno de pruebas pertinente y comprobé si es cierto según lo que acabo de comentar, que CDC sí que funciona ante cargas masivas aún cuando estamos en modo de recuperación BULK-LOGGED. No es el momento de que os exponga aquí los scripts con los que lo he probado, porque en un futuro post ya se subirán los scripts del Jumpstart donde aparecerá entre otros el de CDC; pero como a veces una imagen vale más que mil palabras, aquí tenéis el screenshot que demuestra que CDC funciona con una operación bulk insert sobre una tabla auditada y una base de datos en modo de recuperación BULK LOGGED.


Lo que veis en el screenshot son los cambios en los datos ocurridos en la tabla dbo.Employee desde el principio de los tiempos (solo le hice unas pocas modificaciones ;). Lo que veis marcado en rojo con operación = 2 (INSERT) con los números LSN acabados en 7A002, 7A003 y 7A004 es el resultado de una carga masiva de 3 filas en la tabla, precisamente con los datos que veis (employeeid, lastname y firstname)

Evidentemente, que funcione CDC ante una carga masiva teniendo el modo de recuperación Bulk-logged quiere decir que no estamos ahorrándonos escrituras en el log de transacciones, por lo que tendrás que tenerlo en cuenta si sigues una política de cambios a bulk-logged para mejorar el rendimiento de algunas cargas masivas cuando las realices sobre tablas auditadas mediante CDC.

También comento que hice la misma prueba con una importación de un millón de registros pero los resultados no los pongo aquí puesto que aparece una pequeña incongruencia propia de la versión beta que es, que se sale del ámbito del post…pero probado está ;).

lunes, 25 de febrero de 2008

Windows Vista SP1

Una de las muchas mejoras que nos vienen con Windows Vista SP1 es la del soporte de 64-bits para el proveedor OLEDB de Microsoft (MSDASQL). Este, actuará como puente para una gran variedad de drivers ODBC que no funcionaban bajo arquitecturas de 64-bits.

Gracias a ello, se simplifica la migración de aplicaciones sobre plataformas de 32-bits a plataformas de 64-bits.

Podeis leer mas acerca de las mejoras incluidas en Windows Vista SP1 en el siguiente enlace.

Por cierto, se ha habilitado la descarga de la versión RTM de Windows Vista SP1 a los subscriptores MSDN (link)

lunes, 21 de enero de 2008

Doblando mi residencia ;)

Debido a mi reciente incorporación a Solid Quality Mentors , los futuros posts los realizaré tambien sobre el blog que tenemos el resto de compañeros y yo.

Podeis acceder a traves de la siguiente dirección: http://blogs.solidq.com/ES/ElRinconDelDBA/default.aspx

Un saludo y nos vemos en el otro lado (también)

miércoles, 2 de enero de 2008

Visibilidad de paquetes DTS en SQL Server 2005

Para aquellos que habeis realizado una migración a SQL Server 2005 y teníais Servicios de Transformación de Datos ( DTS ) en SQL Server 2000, Microsoft ha publicado un paquete de compatibilidad para DTS. Dicho pluggin nos permite entre otras cosas poder editar y mantener nuevos DTS desde SQL Server 2005.


Algo que nos puede ocurrir es que queramos que alguno de nuestros compañeros pueda tener acceso a dichos DTS para poder editarlos por ejemplo. Por defecto no tendremos permiso a listar los paquetes y por lo tanto tampoco podremos editarlos. Lo que hay que hacer es asignarle el permiso SELECT al objeto sysdtspackages dentro de la base de datos MSDB.


USE msdb;

GRANT
SELECT
ON
OBJECT::sysdtspackages
TO [usuario];

--REVOKE
SELECT
ON
OBJECT::dbo.sysdtspackages
TO [usuario];


Una gran pega es que este paquete no es compatible con la version de 64-bits por lo que si nuestro servidor de SQL Server utiliza Windows de 64-bits y SQL Server de 64-bits olvidate de esto :(

Para la descarga, visitar este enlace y descargar e instalar SQLServer2005_DTS.msi

miércoles, 7 de noviembre de 2007

Cálculo de letras del DNI mediante T-SQL

IMPORTANTE: Este blog ha sido migrado a https://enriquecatala.com
Subscríbete a mi canal!



Me he visto en la necesidad de obtener la letra del DNI de un conjunto grandísimo de números de DNI.
Por optimización, el DNI se almacenó en un tipo de datos INT ( sin letra ) y se puso como clave primaria, pero por cosas de la vida, he tenido que lanzar un proceso que recalcule las letras de todos los DNI, para algo que no viene al caso


Aquí va la solución:





use GUSENET

go

create table dbo.Nifs(numnif int primary key);

go

insert into dbo.Nifs(numnif) values(12569875)

go

select * from nifs



-- CALCULO DE LA LETRA

DECLARE @letras_nif as CHAR(23)
          

set @letras_nif = 'TRWAGMYFPDXBNJZSQVHLCKE'
          

;

WITH SubSelect AS(
SELECT numnif,
CONVERT(INT,
  FLOOR(
     FLOOR(
           (
            (
             CONVERT(FLOAT,numnif)/23)-FLOOR(CONVERT(FLOAT,numnif)/23)
          )*100
    )*0.23+0.5
 )+1
)AS pos_letra

FROM dbo.Nifs

)

SELECT SUBSTRING(@letras_nif, pos_letra ,1) AS letra,

       str(numnif)+'-'+SUBSTRING(@letras_nif, pos_letra ,1)
          

FROM subselect
           





























Salu2!