<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://geeks.ms/utility/FeedStylesheets/atom.xsl" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><title type="html">La Mina Digital</title><subtitle type="html">Informática de cantera</subtitle><id>http://geeks.ms/blogs/gelexgaray/atom.aspx</id><link rel="alternate" type="text/html" href="http://geeks.ms/blogs/gelexgaray/default.aspx" /><link rel="self" type="application/atom+xml" href="http://geeks.ms/blogs/gelexgaray/atom.aspx" /><generator uri="http://communityserver.org" version="4.1.31106.3070">Community Server</generator><updated>2006-10-10T20:05:00Z</updated><entry><title>Hasta pronto</title><link rel="alternate" type="text/html" href="/blogs/gelexgaray/archive/2008/08/27/hasta-pronto.aspx" /><id>/blogs/gelexgaray/archive/2008/08/27/hasta-pronto.aspx</id><published>2008-08-27T17:48:00Z</published><updated>2008-08-27T17:48:00Z</updated><content type="html">&lt;p&gt;Hace una semana, revisando el blog, me sorprendió ver el mes de mi último post: ¡FEBRERO! Es inútil negarlo... he fracasado como bloguero y he caído en el pozo de todos aquellos que tras el primer año dejan de postear. ¿Por qué?&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;En parte, siento que el blog es una herramienta de profesores y no de alumnos como yo...&lt;/li&gt;&lt;li&gt;En parte, siento que esta vida llena de quehaceres me fuerza a dejar el blog siempre para esos huecos que nunca llegan...&lt;/li&gt;&lt;li&gt;En parte, no me acabo de resignar a que &amp;quot;La Mina Digital&amp;quot; sea un cajón de sastre generalista, y es difícil seguir escribiendo sobre una tecnología con la que actualmente no estoy trabajando...&lt;/li&gt;&lt;li&gt;En parte, porque ya hay demasiados blogs y no veo que éste aporte mucho...&lt;/li&gt;&lt;li&gt;En parte, porque tal vez me esté haciendo viejo... Bueno, eso no.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Espero que hayáis pasado un buen rato leyendo esto. Yo me he divertido... pero ha llegado el momento de ampliar horizontes. Aprender nuevas materias, tal vez desarrollar algo interesante, o quién sabe... tal vez volver a bloguear. Eso nunca se sabe.&lt;br /&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=96212" width="1" height="1"&gt;</content><author><name>gelexgaray</name><uri>http://geeks.ms/members/gelexgaray/default.aspx</uri></author></entry><entry><title>El AJK, la máquina de pila y el CLR</title><link rel="alternate" type="text/html" href="/blogs/gelexgaray/archive/2008/02/21/el-ajk-la-m-225-quina-de-pila-y-el-clr.aspx" /><id>/blogs/gelexgaray/archive/2008/02/21/el-ajk-la-m-225-quina-de-pila-y-el-clr.aspx</id><published>2008-02-21T22:59:00Z</published><updated>2008-02-21T22:59:00Z</updated><content type="html">&lt;p&gt;Iba de camino al trabajo leyendo la MSDN Magazine, cuando me ha llamado la atención un artículo titulado &amp;quot;Cree un compilador de lenguaje para .Net Framework&amp;quot; (&lt;a href="http://msdn.microsoft.com/msdnmag/issues/08/02/CompilerWriting/?loc=es"&gt;http://msdn.microsoft.com/msdnmag/issues/08/02/CompilerWriting/?loc=es&lt;/a&gt;). Me ha hecho sentirme joven y recordar a JosuKa: mi profe de compiladores en la universidad.&lt;br /&gt;&lt;br /&gt;Lo primero por lo que he recordado a JosuKa es la similitud entre el CLR y la &amp;quot;máquina de pila&amp;quot; que inventó y desarrolló para sus prácticas. JosuKa... ¡eras un visionario! &lt;br /&gt;&lt;br /&gt;Para los que no sepáis de qué hablo... JosuKa nos ponía como ejercicio el desarrollo de un compilador para un lenguaje y máquina objetivo ficticios. El lenguaje se llamaba &amp;quot;AJK&amp;quot; (que la verdad, no se que rayos significa) y generaba código para...¡¡tachán!! ... ¡¡¡la máquina de pila!!!. Precisamente Joel Pobar, el autor del artículo que os comentaba, nos presenta el CLR como una máquina de pila... muy similar a la de JosuKa (como no podría ser de otra forma). &lt;br /&gt;&lt;br /&gt;Lo segundo que he recordado, es que en nuestras prácticas usábamos herramientas específicas para el desarrollo de compiladores, cosa que en el artículo no se hace.&lt;br /&gt;• Par el escáner usábamos Flex, un clon del Lex. &lt;br /&gt;• Para el parser usábamos Bison, compatible con Yacc.&lt;br /&gt;• El generador de código se escribía en C, por medio de una librería proporcionada por JosuKa. En el artículo se utiliza System.Reflection.Emit&lt;br /&gt;(Más sobre Lex, Yacc, Flex y Bison en &lt;a href="http://dinosaur.compilertools.net"&gt;http://dinosaur.compilertools.net&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;Me he puesto a hurgar un poco por Internet y he encontrado unos clones de Lex y Yacc para .Net:&amp;nbsp; GPLEX y GPPG (&lt;a href="http://www.plas.fit.qut.edu.au/gppg/"&gt;http://www.plas.fit.qut.edu.au/gppg/&lt;/a&gt; y &lt;a href="http://www.plas.fit.qut.edu.au/gplex/"&gt;http://www.plas.fit.qut.edu.au/gplex/&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;Por último, el artículo da unas pinceladas sobre cómo se enlaza el código en los lenguajes dinámicos... tan de moda con el DLR de Silverlight y con mi dulcemente odiado JavaScript (no es nada personal, mi querido lenguaje, todo es fruto de la incomprensión).&lt;br /&gt;&lt;br /&gt;De verdad que os recomiendo la lectura del artículo... y seguro que añadiendo al &amp;quot;pack&amp;quot; estas herramientas, ¡podéis divertiros un buen rato! &lt;br /&gt;&lt;br /&gt;¿Y por qué os cuento todo esto? Pues porque para mi, la moraleja es que todos los procesadores (reales o virtuales) son simples máquinas de pila, y todos los compiladores &amp;quot;comparten el 99% de los genes&amp;quot;.&lt;br /&gt;&lt;br /&gt;No se si este conocimiento sirve realmente de algo... de hecho, ni siquiera puedo decir que te vaya a ayudar a programar mejor (y si puedes programar peor, si caes en el antipatrón de la optimización temprana). Ocurre lo mismo que con los coches: para conducir un coche no es necesario saber cómo funciona un motor de explosión... y sin embargo, para quien le gustan los coches, este es un conocimiento sin el que símplemente no podría vivir.&lt;br /&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=73393" width="1" height="1"&gt;</content><author><name>gelexgaray</name><uri>http://geeks.ms/members/gelexgaray/default.aspx</uri></author><category term="Herramientas" scheme="http://geeks.ms/blogs/gelexgaray/archive/tags/Herramientas/default.aspx" /><category term="Framework" scheme="http://geeks.ms/blogs/gelexgaray/archive/tags/Framework/default.aspx" /></entry><entry><title>Herramientas para diagnóstico de problemas en el MSDTC</title><link rel="alternate" type="text/html" href="/blogs/gelexgaray/archive/2007/12/13/herramientas-para-diagn-243-stico-de-problemas-en-el-msdtc.aspx" /><id>/blogs/gelexgaray/archive/2007/12/13/herramientas-para-diagn-243-stico-de-problemas-en-el-msdtc.aspx</id><published>2007-12-13T19:13:00Z</published><updated>2007-12-13T19:13:00Z</updated><content type="html">&lt;p&gt;Ayer estuve peleándome con un servidor en el que había dejado de funcionar el MSDTC (había dejado de funcionar con un poco de ayuda por mi parte, he de admitir). Bueno, el tema es que tratando de diagnosticar el problema y tras ver que las trazas del MSDTC muchas veces dicen bien poco (TRANSACTION_ABORTED y poco más), di con dos herramientas que me resultaron bastánte útiles para diagnosticar problemas relacionados con la red. Allá van:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;div&gt;DTCTest: &lt;a href="http://www.sqldev.net/misc/DTCTest.htm"&gt;http://www.sqldev.net/misc/DTCTest.htm&lt;/a&gt;&amp;nbsp;. Esta es una herramienta que permite ir probando si las transacciones distribuidas se inician y finalizan correctamente desde cada uno de los nodos de la red. Se puede probar a iniciar y finalizar (con éxito o con un rollback) la transacción, especificando qué msdtc coordinará, y sobre qué SQL Server se realizará. Permite además especificar la sentencia SQL con la que se testeará y si se iniciará la transacción con ODBC u OLEDB.&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;DTCPing: &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=5E325025-4DCD-4658-A549-1D549AC17644&amp;amp;displaylang=en"&gt;http://www.microsoft.com/downloads/details.aspx?FamilyID=5E325025-4DCD-4658-A549-1D549AC17644&amp;amp;displaylang=en&lt;/a&gt;&amp;nbsp;. Esta herramienta se lanza en los dos nodos que participan en una transacción distribuida y verifica que no hay ningún impedimento de comunicaciones para que se pueda iniciar la transacción (ambos nodos pueden resolver el nombre de su &amp;quot;oponente&amp;quot;, se pueden acceder entre sí por RPC... etc).&lt;/div&gt;&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;¡Espero que no necesitéis usar ninguna de las dos!&lt;br /&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=56920" width="1" height="1"&gt;</content><author><name>gelexgaray</name><uri>http://geeks.ms/members/gelexgaray/default.aspx</uri></author><category term="Herramientas" scheme="http://geeks.ms/blogs/gelexgaray/archive/tags/Herramientas/default.aspx" /></entry><entry><title>Guía de diseño para pantallas táctiles</title><link rel="alternate" type="text/html" href="/blogs/gelexgaray/archive/2007/10/29/gu-237-a-de-dise-241-o-para-pantallas-t-225-ctiles.aspx" /><id>/blogs/gelexgaray/archive/2007/10/29/gu-237-a-de-dise-241-o-para-pantallas-t-225-ctiles.aspx</id><published>2007-10-29T11:57:00Z</published><updated>2007-10-29T11:57:00Z</updated><content type="html">&lt;p&gt;Navegando por ahí he encontrado una interesante guía de diseño para aplicaciones que corren en pantallas táctiles. Viene de SAP, que curiosamente tiene un estupendo sitio web sobre usabilidad... ¿lo utilizarán? ;-). La guía la&amp;nbsp;podéis encontrar en &lt;a href="http://www.sapdesignguild.org/resources/TSDesignGL/Index.htm"&gt;http://www.sapdesignguild.org/resources/TSDesignGL/Index.htm&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=46395" width="1" height="1"&gt;</content><author><name>gelexgaray</name><uri>http://geeks.ms/members/gelexgaray/default.aspx</uri></author><category term="Usabilidad" scheme="http://geeks.ms/blogs/gelexgaray/archive/tags/Usabilidad/default.aspx" /></entry><entry><title>La estética también tiene leyes</title><link rel="alternate" type="text/html" href="/blogs/gelexgaray/archive/2007/07/08/la-est-233-tica-tambi-233-n-tiene-leyes.aspx" /><id>/blogs/gelexgaray/archive/2007/07/08/la-est-233-tica-tambi-233-n-tiene-leyes.aspx</id><published>2007-07-08T15:11:00Z</published><updated>2007-07-08T15:11:00Z</updated><content type="html">
&lt;p&gt;Cuando estudiaba en la universidad, recuerdo que me explicaron tan mal las leyes de la Gestalt, que acabé por no prestarles ninguna atención. Señor profesor, si me lee... no se lo tome a mal: no es nada personal contra usted. En general, en las universidades tiende a explicarse las cosas lo más alejadas de la aplicación práctica posible, y las leyes de la Gestalt sacadas del contexto del diseño de interfaces de usuario, parecen un conjunto de verdades de perogrullo meditadas en un momento de iluminación etílica.&lt;/p&gt;
 
&lt;p&gt;Sin embargo, según pasan los años, me doy cuenta de que lo que deberían ser verdades de perogrullo, muchas veces se discuten en los equipos de desarrollo. Creedme...&amp;nbsp;lleva mucho, muchísimo tiempo tomar una decisión con argumentos del tipo &amp;quot;a mi me gusta así&amp;quot; cuando probablemente podrían tomarse en un trís siguiendo&amp;nbsp;criterios de la Gestalt. En este post pretendo hacer un repaso de las seis leyes de la Gestalt desde la perspectiva práctica del diseñador de interfaces Windows. Lo primero, para el que no haya oído hablar de estas leyes, podéis consultar la teoría &lt;a href="http://es.wikipedia.org/wiki/Psicolog%C3%ADa_de_la_Gestalt"&gt;aquí&lt;/a&gt;.&lt;/p&gt;
 &lt;h3&gt;Leyes de la proximidad y de la semejanza&lt;/h3&gt; 
&lt;p&gt;Agrupo estas dos leyes porque suele ser habitual aplicarlas en conjunto. La idea es que los elementos que están próximos, o los elementos que tienen una forma semejante, tienden a considerarse en su conjunto. En las interfaces de usuario, esto nos lleva a las &lt;b&gt;agrupaciones&lt;/b&gt; de controles.&lt;/p&gt;
 
&lt;ul&gt; 
&lt;li&gt;Si un grupo de controles se refieren a un mismo concepto, agrupándolos facilitaremos la comprensión de cada uno de los elementos (porque la mente humana los considerará como parte de un &amp;quot;todo&amp;quot;). Lo mejor es que lo veamos con un ejemplo:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://geeks.ms/blogs/gelexgaray/WindowsLiveWriter/Laestticatambintieneleyes_A91C/agrupacion_mala%5B5%5D.png"&gt;&lt;img src="http://geeks.ms/blogs/gelexgaray/WindowsLiveWriter/Laestticatambintieneleyes_A91C/agrupacion_mala_thumb%5B3%5D.png" height="143" width="357" alt="" /&gt;&lt;/a&gt; &lt;br /&gt;Agrupación pésima (sacada de un ejemplo real). El grupo &amp;quot;archivo&amp;quot; se percibe como algo separado y distinto de la opción &amp;quot;generar script&amp;quot;. De esta forma, no se entiende que el nombre de archivo que se solicita sea el nombre del script que se va a generar. La forma correcta de diseñar este diálogo sería:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://geeks.ms/blogs/gelexgaray/WindowsLiveWriter/Laestticatambintieneleyes_A91C/agrupacion_buena%5B3%5D.png"&gt;&lt;img src="http://geeks.ms/blogs/gelexgaray/WindowsLiveWriter/Laestticatambintieneleyes_A91C/agrupacion_buena_thumb%5B1%5D.png" height="165" width="368" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&lt;br /&gt;En este ejemplo estamos aplicando:&lt;/li&gt;
 
&lt;ul&gt; 
&lt;li&gt;Ley de la agrupación: se entiende que el textbox espacifica el nombre del archivo por el simple hecho de estar agrupado con el botón &amp;quot;archivo&amp;quot; y el checkbox de &amp;quot;generar script&amp;quot;&lt;/li&gt;
 
&lt;li&gt;Ley de la similitud: el botón &amp;quot;OK&amp;quot; se llama ahora &amp;quot;Aceptar&amp;quot;,&amp;nbsp;con lo que se entiende que tiene una función idéntica al resto de botones &amp;quot;Aceptar&amp;quot; de Windows. Por otra parte el botón Archivo tiene puntos suspensivos, por lo que se entiende que sacará un cuadro de diálogo adicional.&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
 
&lt;li&gt;Sobre la ley de la semejanza, hay que tratar de parecerse tanto a otras aplicaciones como a nosotros mismos. Trata de hacer tus interfaces siguiendo las guías de diseño de Windows. Trata de que tu aplicación se parezca a una que sea el referente en tu sector (todos los procesadores de texto acaban pareciéndose al que domina el mercado... pasó en su día con WordStar, luego con WordPerfect y ahora con Word). Por último, trata de que tu aplicación se parezca a sí misma: los diálogos deben ser similares, los conceptos deben expresarse con los mismos términos, y los iconos deben seguir los mismos paradigmas. Si dos cosas tienen un aspecto similar, el cerebro tiende a relacionarlas... y todo el conocimiento que haya adquirido sobre el modelo antiguo, lo aplicará al modelo nuevo. ¡Resultar familiar es la forma de tener que ahorrarte escribir un manual! ;-)&lt;/li&gt;
&lt;/ul&gt;
 &lt;h3&gt;Ley del cierre y ley de continuidad&lt;/h3&gt; 
&lt;p&gt;Estas leyes son más aplicables al diseño gráfico puro y duro que a la usabilidad, pero también pueden servirnos de ayuda. Básicamente, dicen que el cerebro tiende a cerrar cualquier figura a la que le falta un trozo, y que el cerebro continúa cualquier patrón que se interrumpe.&lt;/p&gt;
 
&lt;p&gt;Su aplicación práctica principal están en mostrar más información de la que cabe en pantalla. Fijémonos en un procesador de texto:&lt;/p&gt;
 
&lt;blockquote&gt; 
&lt;p&gt;&lt;a href="http://geeks.ms/blogs/gelexgaray/WindowsLiveWriter/Laestticatambintieneleyes_A91C/image%7B0%7D%5B5%5D.png"&gt;&lt;img src="http://geeks.ms/blogs/gelexgaray/WindowsLiveWriter/Laestticatambintieneleyes_A91C/image%7B0%7D_thumb%5B3%5D.png" style="border:0px none;margin:0px 1px 0px 0px;" border="0" height="480" width="558" alt="" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;/blockquote&gt;
 
&lt;p&gt;Sólo vemos la esquina superior izquierda de un rectángulo, pero ya sabemos que representa parte de una hoja de papel (nuestro cerebro se ha encargado de cerrar la figura). Esto nos indica que lo que escribimos, se sitúa en determinado punto de la hoja de papel, y además sabemos que hay más sitio que no estamos viendo ahora mismo en pantalla. También se emplea la ley de continuidad para apoyar esta idea (se ha empleado un patrón gris, distinto del fondo blanco de la hoja, para reforzar la idea de que estamos escribiendo sobre un papel del que sólo vemos un trozo).&lt;/p&gt;
 &lt;h3&gt;Ley de simetría&lt;/h3&gt; 
&lt;p&gt;Literalmente dice &amp;quot;Las imágenes simétricas son percibidas como iguales, como un solo elemento, en la distancia&amp;quot;. Esta es otra ley más aplicable al diseño puro y duro que a la usabilidad, pero sí que podemos tomar una lección: si no puedes usar grupos, utiliza la simetría. Si no nos cabe todo a un lado, podemos usar el lado opuesto... que parecerá que se refieren a lo mismo. Lo mejor es fijarse en una herramienta con muchos &amp;quot;toolbox&amp;quot; como Visual Studio. Todos los toolbox no cabrían en uno de los dos lados de la pantalla... colocando áreas de toolbox a la izquierda y a la derecha, se ha aumentado el espacio disponible para herramientas. Como las áreas de herramientas son simétricas, se perciben como iguales (se ve como natural que ámbas áreas contengan lo mismo, cuando en realidad no constituyen un grupo).&lt;/p&gt;
 
&lt;blockquote&gt; 
&lt;p&gt;&lt;a href="http://geeks.ms/blogs/gelexgaray/WindowsLiveWriter/Laestticatambintieneleyes_A91C/image%7B0%7D%5B9%5D.png"&gt;&lt;img src="http://geeks.ms/blogs/gelexgaray/WindowsLiveWriter/Laestticatambintieneleyes_A91C/image%7B0%7D_thumb%5B5%5D.png" style="border:0px none;" border="0" height="385" width="640" alt="" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;/blockquote&gt;
 &lt;h3&gt;Ley de comunidad&lt;/h3&gt; 
&lt;p&gt;&amp;quot;Muchos elementos moviéndose en la misma dirección son percibidos como un único elemento&amp;quot;. De nuevo esta ley es más aplicable al diseño que a la usabilidad. Yo esta ley no la aplicaría, porque el movimiento dentro de un formulario Windows es algo que debería evitarse. Sin embago, también tiene su aplicación en los controles &amp;quot;Marquee&amp;quot; o marquesina. El típico control que muestra información bursátil. Se muestra mucha información en poco espacio, y además la información se percibe como un &amp;quot;todo&amp;quot;.&lt;/p&gt;
 &lt;h3&gt;Conclusión&lt;/h3&gt; 
&lt;p&gt;Fíjate mucho en los programas de los demás, y fíjate en los patrones que siguen. Suelen estár ahí por algo... y aunque muchas veces creemos que en el diseño de un formulario prima la estética, lo cierto del caso es que se suelen tener en cuenta factores psicológicos que a cualquiera de nosotros (humildes programadores) se nos escapan. Trata de convencer a tus jefes de lo importante que es contratar a un experto en usabilidad, y si no te queda más remedio que tomar tú mismo las decisiones, innova todo lo que quieras, pero en áreas distintas a la interfaz de usuario. Revisa las guias de diseño de Windows, y recuerda... &amp;quot;inspirarse&amp;quot; en un programa conocido suele ser una buena idea: ¿por qué crees que todos los navegadores web se parecen al veterano &lt;a href="http://en.wikipedia.org/wiki/Mosaic_%28web_browser%29"&gt;Mosaic&lt;/a&gt;?&lt;/p&gt;
&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=19143" width="1" height="1"&gt;</content><author><name>gelexgaray</name><uri>http://geeks.ms/members/gelexgaray/default.aspx</uri></author><category term="Usabilidad" scheme="http://geeks.ms/blogs/gelexgaray/archive/tags/Usabilidad/default.aspx" /></entry><entry><title>¿Depurar un script SSIS?</title><link rel="alternate" type="text/html" href="/blogs/gelexgaray/archive/2007/04/18/depurar-un-script-ssis.aspx" /><id>/blogs/gelexgaray/archive/2007/04/18/depurar-un-script-ssis.aspx</id><published>2007-04-18T18:58:00Z</published><updated>2007-04-18T18:58:00Z</updated><content type="html">&lt;P&gt;Una de las mayores pegas que tiene Integration Services es el hecho de no poder depurar los scripts... bueno, ese y que el nodo script no soporte C# como lenguaje (sólo soporta Visual Basic). Si bien ninguno de los dos problemas tiene solución, el primero puede mitigarse en gran mediad con la capacidad que nos ofrece SSIS para lanzar trazas desde nuestros scripts. ¿Cómo se hace? ¡Atentos!&lt;/P&gt;
&lt;H1&gt;&lt;FONT size=3&gt;Los visores de datos: el script como una caja negra&lt;/FONT&gt;&lt;/H1&gt;
&lt;P&gt;Lo más sencillo para tratar de averiguar qué ocurre dentro de un script es observar qué salidas nos ofrece fuera. Para eso siempre podemos usar los "data viewers", que se añaden directamente al flujo de salida o de entrada en un script y nos muestran el contenido de los buffers. Esto está bien para detectar problemas serios, pero la mayoría de las veces no será de gran ayuda. En la imagen, tenemos un script que genera números del 1 al 100 y una transformación que los cuenta... si vemos que la salida es anormal, siempre podemos entrar en el código del script e inspeccionarlo en busca del comportamiento anómalo. Por cierto... en este sentido, ayuda el que los scripts sean sencillos y hagan el mínimo posible de cosas.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://geeks.ms/blogs/gelexgaray/WindowsLiveWriter/DepurarunscriptSSIS_E3DC/image08.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH:0px;BORDER-LEFT-WIDTH:0px;BORDER-BOTTOM-WIDTH:0px;BORDER-RIGHT-WIDTH:0px;" height=347 src="http://geeks.ms/blogs/gelexgaray/WindowsLiveWriter/DepurarunscriptSSIS_E3DC/image0_thumb6.png" width=582 border=0&gt;&lt;/A&gt;&lt;/P&gt;
&lt;H1&gt;&lt;FONT size=3&gt;Cuando el exterior no ayuda, lo importante está en el interior.&lt;/FONT&gt;&lt;/H1&gt;
&lt;P&gt;Cuando el problema no es obvio, llega el momento de depurar. Lo que nos dice el sentido común es que pongamos un breakpoint en nuestro procedimiento, y que lo vayamos observando paso a paso:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://geeks.ms/blogs/gelexgaray/WindowsLiveWriter/DepurarunscriptSSIS_E3DC/image011.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH:0px;BORDER-LEFT-WIDTH:0px;BORDER-BOTTOM-WIDTH:0px;BORDER-RIGHT-WIDTH:0px;" height=439 src="http://geeks.ms/blogs/gelexgaray/WindowsLiveWriter/DepurarunscriptSSIS_E3DC/image0_thumb7.png" width=585 border=0&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;¿Qué ocurre cuando ejecutamos el paquete SSIS? Absolutamente nada: no se detiene. Los breakpoints no funcionan para los scripts de SSIS (¡¡Microsoft, Socorro!!). Mientras los programadores de Redmond acudan en nuestra ayuda y solucionen este problema, veamos qué podemos hacer para sobrevivir:&lt;/P&gt;
&lt;H2&gt;&lt;FONT size=3&gt;Un punto de ruptura cutre: El MessageBox&lt;/FONT&gt;&lt;/H2&gt;
&lt;P&gt;&lt;A href="http://geeks.ms/blogs/gelexgaray/WindowsLiveWriter/DepurarunscriptSSIS_E3DC/image014.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH:0px;BORDER-LEFT-WIDTH:0px;BORDER-BOTTOM-WIDTH:0px;BORDER-RIGHT-WIDTH:0px;" height=442 src="http://geeks.ms/blogs/gelexgaray/WindowsLiveWriter/DepurarunscriptSSIS_E3DC/image0_thumb8.png" width=589 border=0&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;Afortunadamente, tenemos una chapucilla que nos permitirá parar la ejecución de un script SSIS: El MessageBox. Alguno dirá... tantos años de evolución para volver a sacar mensajitos de "estoy aqui" o "voy por acá". Sí amigos... las viejas soluciones nunca mueren: "la chapu funciona" (máxima que aprendí en uno de las empresas en las que he trabajado hasta ahora). Colocar un "MessageBox.Show()" hará que el flujo del script se detenga hasta que pulsemos "OK".&lt;/P&gt;
&lt;H1&gt;&lt;FONT size=3&gt;Observar el valor de una variable privada&lt;/FONT&gt;&lt;/H1&gt;
&lt;P&gt;Cualquiera podría decir, si puedo sacar un MessageBox, puedo mostrar el valor de una variable privada. Cierto... sólo que si queremos saber el valor de una varible privada a lo largo de todas las iteraciones de un bucle, detener la ejecución a cada paso puede ser un tormento. Por fortuna, SSIS nos permite utilizar su potente soporte de Logging desde nuestros scripts. Para eso, vamos al menú SSIS -&amp;gt; Logging, habilitamos un proveedor de logging, y en la pestaña de "Details" seleccionamos la entrada "ScriptComponentLogEntry".&lt;/P&gt;
&lt;P&gt;&lt;A href="http://geeks.ms/blogs/gelexgaray/WindowsLiveWriter/DepurarunscriptSSIS_E3DC/image05.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH:0px;BORDER-LEFT-WIDTH:0px;BORDER-BOTTOM-WIDTH:0px;BORDER-RIGHT-WIDTH:0px;" height=480 src="http://geeks.ms/blogs/gelexgaray/WindowsLiveWriter/DepurarunscriptSSIS_E3DC/image0_thumb1.png" width=571 border=0&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;Eso habrá habilitado el logeo a los componentes script. En realidad ni siquiera es necesario especificar un destino para el log: bastará con mostrar la ventana "Log Events" (View -&amp;gt; Other Windows -&amp;gt; Log Events).... pero ojo, que el visor de logs tiene sus limitaciones que veremos más adelante.&lt;/P&gt;
&lt;P&gt;Ahora sólo tenemos que usar el método "Log" que nuestro script habrá heredado de su clase base, de la siguiente forma:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://geeks.ms/blogs/gelexgaray/WindowsLiveWriter/DepurarunscriptSSIS_E3DC/image011%5B1%5D.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH:0px;BORDER-LEFT-WIDTH:0px;BORDER-BOTTOM-WIDTH:0px;BORDER-RIGHT-WIDTH:0px;" height=480 src="http://geeks.ms/blogs/gelexgaray/WindowsLiveWriter/DepurarunscriptSSIS_E3DC/image0_thumb3.png" width=636 border=0&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;Me.Log( messageText, dataCode, dataBytes() )&lt;/P&gt;
&lt;P&gt;El método Log admite tres parámetros:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;La cadena de texto que queremos mostrar en el log 
&lt;LI&gt;Un valor numérico que queramos loguear: Cuidado, esta opción sólo funciona si hemos activado un destino para el log, si estamos viendo los logs con el visor de logs, curiosamente no se ve su valor 
&lt;LI&gt;Un buffer de datos que queramos loguear. Ocurre lo mismo que con la opción anterior, sólo sirve si definimos un destino para los logs (no funciona con el visor de logs).&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Como el visor de logs no permite ver los valores asignados a dataCode y dataBytes, generalmente nos convendrá loguear todo dentro de la cadena de texto, de la siguiente forma:&lt;/P&gt;
&lt;P&gt;Me.Log( "El valor de i es " + i, 0,&amp;nbsp;Nothing )&lt;/P&gt;
&lt;P&gt;En fin, espero que esto os sirva para cogerle un poco más de cariño a la transformación Script, que no es tan mala como parece...&lt;/P&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=13381" width="1" height="1"&gt;</content><author><name>gelexgaray</name><uri>http://geeks.ms/members/gelexgaray/default.aspx</uri></author><category term="Integration Services" scheme="http://geeks.ms/blogs/gelexgaray/archive/tags/Integration+Services/default.aspx" /></entry><entry><title>Material de la charla "Olap aún más fácil"</title><link rel="alternate" type="text/html" href="/blogs/gelexgaray/archive/2007/03/22/material-de-la-charla-olap-a-n-m-s-f-cil.aspx" /><link rel="enclosure" type="application/x-zip-compressed" length="3233430" href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Components.PostAttachments/00.00.01.21.33/Material.zip" /><id>/blogs/gelexgaray/archive/2007/03/22/material-de-la-charla-olap-a-n-m-s-f-cil.aspx</id><published>2007-03-22T20:31:00Z</published><updated>2007-03-22T20:31:00Z</updated><content type="html">&lt;P&gt;Algún día tenía que ser, y este martes me toco a mi dar la charla mensual del grupo de usuarios de Euskadi, Artalde.NET. La charla fue una introducción muy básica a lo que es un sistema OLAP, y estuvo compuesta de:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Una pequeña charleta de 30 minutos, en la que vimos conceptos básicos.&lt;/LI&gt;
&lt;LI&gt;Una demostración de hora y media, en la que hicimos una demo con un ETL y un cubo muy básicos... vamos, que nos marcamos un "OLAP Mundo" (por cierto... en la charla nadie se rio con ese chiste... ¿tan malo será?)&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;La verdad que tuvo bastante buena acogida, creo. Bueno, a lo mejor es que soy un optimista y no veía los bostezos de la gente... concentrado en ver cómo las transformaciones del dtsx cambiaban de color según pasaba el flujo de datos. Hubo algo menos de 40 personas, una de esas charlas en familia, en la que la gente que va de verdad está interesada en el tema. La gente se animó bastante a participar, y creo que el grupo de Artalde está cogiendo una "clientela fija" de fans incondicionales que son estupendos.&lt;/P&gt;
&lt;P&gt;En fin, voy a dejar de enrollarme e iré al grano. Voy a dejar aquí el material de la charla, por si a alguien le interesa. Os dejo:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Las transparencias PowerPoint de la presentación.&lt;/LI&gt;
&lt;LI&gt;La solución que contiene el ETL, y el cubo OLAP tal y como quedó al final. &lt;/LI&gt;
&lt;LI&gt;Los datos de origen y el script de creación del Data Warehouse.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;De los cubos no sacaréis mucha información, porque básicamente está construido a partir de datos aleatorios. Bueno... digamos que cogí la lista de clientes de AdventureWorks y la convertí en una lista de "nacimientos" (con el peso, talla y grupo sanguíneo del niño). Lugo le añadí datos sobre supuestos factores que determinaban el éxito social de esos retoños, y pretendía ser un "serio" estudio sobre la influencia que pueden tener factores como el signo del zodíaco en parámetros como el salario medio anual. Vamos... ¡verdadero papel mojado! Fue divertido... :-)&lt;/P&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=12133" width="1" height="1"&gt;</content><author><name>gelexgaray</name><uri>http://geeks.ms/members/gelexgaray/default.aspx</uri></author><category term="Artalde.NET" scheme="http://geeks.ms/blogs/gelexgaray/archive/tags/Artalde.NET/default.aspx" /></entry><entry><title>Aplicaciones prácticas de los algoritmos de minería de datos</title><link rel="alternate" type="text/html" href="/blogs/gelexgaray/archive/2007/03/01/aplicaciones-pr-cticas-de-los-algoritmos-de-miner-a-de-datos.aspx" /><id>/blogs/gelexgaray/archive/2007/03/01/aplicaciones-pr-cticas-de-los-algoritmos-de-miner-a-de-datos.aspx</id><published>2007-03-01T19:41:00Z</published><updated>2007-03-01T19:41:00Z</updated><content type="html">&lt;P&gt;Hoy durante la comida, ha surgido un tema de conversación interesante: qué fácil resulta añadir nuevos algoritmos de minería de datos a SQL Server 2005... pero, ¿para qué puede servir? Lo cierto del caso es que meditando sobre el tema, no se me ha ocurrido ninguna aplicación práctica que no esté debidamente cubierta con los algoritmos "de serie". Todavía no estoy muy puesto en este tema, pero voy a hacer un esfuerzo mental y vamos a ver qué algoritmos trae Analysis Services y para qué los podemos utilizar.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;STRONG&gt;Algoritmo Naive Bayes&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Empezamos por este porque es el algoritmo que primero se suele utilizar para explorar datos. Básicamente, este algoritmo busca correlaciones entre atributos. Cuando no tenemos muy claro qué atributo se puede predecir en función de otros, una técnica muy habitual es tratar de utilizar el algoritmo de Naive Bayes tratando de predecir el valor de todos los atributos en función de todos los atributos (un "todos contra todos"). El resultado de esta orgía de correlaciones suele ser un modelo en el que tenemos más o menos claro qué vamos a poder predecir en esos datos.&lt;/P&gt;
&lt;P&gt;Otra ventaja de este algoritmo es que se entrena muy rápido... pero su desventaja es que no es muy preciso. Vamos, yo lo usaría para:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Exploración inicial de los datos&lt;/LI&gt;
&lt;LI&gt;Tareas de clasificación, en las que el rendimiento sea crítico. Se me ocurre, por ejemplo, entornos en tiempo real en los que queramos detectar entradas anómalas, validaciones, clasificaciones y filtrados de mensajes... etc.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&lt;STRONG&gt;Decision Trees (Árboles de decisión)&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Los árboles de decisión son clarísimamente una herramienta potentísima de clasificación... de hecho, son probablemente el mejor algoritmo que podemos utilizar para clasificar. Básicamente, construyen un arbol del que se pueden extraer reglas, del estilo "Si eres hombre, tienes unos ingresos superiores a 'X', y eres comprador de revistas de coches... la probabilidad de que tengas coche es del 90%".&lt;/P&gt;
&lt;P&gt;Nos pueden servir para tareas como:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Clasificación en general&lt;/LI&gt;
&lt;LI&gt;Validaciones. Podemos detectar elementos anómalos en función de si encajan o no con&amp;nbsp;las reglas surgidas del árbol&amp;nbsp;(por ejemplo, "si tienes coche, menos de 20 años y estas en paro... probablemente mientas")&lt;/LI&gt;
&lt;LI&gt;Predecir el valor de un atributo con precisión&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&lt;STRONG&gt;Clustering&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Sirve sobre todo para buscar elementos afines dentro de un conjunto. Por ejemplo, podemos usarlo para saber que en una población hay hombres y mujeres&amp;nbsp;jovenes solteros,&amp;nbsp; hombres mayores solteros, hombres y mujeres mayores casados... pero no mujeres mayores solteras.&lt;/P&gt;
&lt;P&gt;Nos puede servir para:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Segmentar un mercado.&lt;/LI&gt;
&lt;LI&gt;Validaciones (las entradas que no pertenecen a un cluster, pueden ser "outliners" o elementos anómalos).&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&lt;STRONG&gt;Time Series (Series temporales)&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Este algorimo es específico para predecir el valor de una magnitud en función del tiempo.&lt;/P&gt;
&lt;P&gt;Por ejemplo:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Análisis bursátiles... ¿subirá o bajará el IBEX mañana?&lt;/LI&gt;
&lt;LI&gt;Predicción de una magnitud analógica, en general.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&amp;nbsp;&lt;STRONG&gt;Sequence clustering&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Tambien es bastante específico para detectar secuencias típicas dentro de un conjunto de eventos. Por ejemplo... saber en qué orden&amp;nbsp;hace click la gente en las noticias de&amp;nbsp;una web, puede ayudarnos a ordenar los titulares de arriba a abajo y de derecha a izquierda.&lt;/P&gt;
&lt;P&gt;Usos típicos:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Estudio de secuencias de eventos&lt;/LI&gt;
&lt;LI&gt;Detección de algunas anomalías de comportamiento (eventos que llegan fuera de secuencia)&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&lt;STRONG&gt;Association rules (Reglas de asociación)&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Este se suele usar casi exclusivamente para análisis de cesta de la compra. Detecta asociaciones comunes entre elementos (por ejemplo, quien compra cerveza suele comprar también palitos salados).&lt;/P&gt;
&lt;P&gt;Usos típicos:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Análisis de la cesta de la compra&lt;/LI&gt;
&lt;LI&gt;Ofrecer recomendaciones al comprador: ¿has comprado cerveza, seguro que no quieres palitos salados?&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&lt;STRONG&gt;Neural Network (Redes neuronales)&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Al igual que los árboles de decisión, este algoritmo también resuelve problemas de clasificación y regresión. Puede ser adecuado para detectar patrones no lineales, difícilemente descriptibles por medio de reglas. Se usa como alternativa al algoritmo de arboles de decisión: lo mejor es probar ambos sobre un mismo problema y utilizar el que mayor acierto nos de en sus predicciones.&lt;/P&gt;
&lt;P&gt;Nos pueden servir para tareas como: 
&lt;UL&gt;
&lt;LI&gt;Las mismas tareas que los árboles de decision, cuando los grupos en los que se divide la población no son lineales. Si no sabes a qué me refiero, imagina la tarea de clasificar puntos en un espacio... cuando no se pueden clasificar fácilmente trazando líneas, el problema no es lineal. 
&lt;LI&gt;Regresiones (es similar a la clasificación, pero cuando se trata de predecir una magnitud contínua).&lt;/LI&gt;&lt;/UL&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Bueno, el caso es que la riqueza de los algoritmos que vienen incorporados con SQL Server es tal, que no se me ha ocurrido ni un sólo escenario en el que se pueda necesitar algo distinto... ¿eres capaz de comentar alguno? La verdad que esta versión del 2005 es impresionante, ¿verdad?&lt;/P&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=11173" width="1" height="1"&gt;</content><author><name>gelexgaray</name><uri>http://geeks.ms/members/gelexgaray/default.aspx</uri></author><category term="Miner&amp;#237;a de datos" scheme="http://geeks.ms/blogs/gelexgaray/archive/tags/Miner_26002300_237_3B00_a+de+datos/default.aspx" /></entry><entry><title>Suprimir los warnings de FxCop para un proxy WCF</title><link rel="alternate" type="text/html" href="/blogs/gelexgaray/archive/2007/02/13/suprimir-los-warnings-fxcop-de-los-proxy-wcf.aspx" /><id>/blogs/gelexgaray/archive/2007/02/13/suprimir-los-warnings-fxcop-de-los-proxy-wcf.aspx</id><published>2007-02-13T20:07:00Z</published><updated>2007-02-13T20:07:00Z</updated><content type="html">&lt;P&gt;Qué "antiestético" es el código con warnings, ¿verdad? Una de las cosas que más me llamó la atención, y tengo que reconocer que para mal, es la cantidad que saltan al pasar el FxCop sobre los proxies que genera Windows Communication Foundation. Da una sensación horrible, y cuando uno suprime los warnings, ver que al regenerar los proxies volvemos a la situación anterior, es tremendamente frustrante. Alguno estará pensando... ¿y qué hace este cenutrio pasando el analizador estático a código generado de forma automática? Bueno... mi problema es que no puedo elegir... al activar el análisis de código en las propiedades de un proyecto, se activa sobre todos los fuentes... incluidos los proxies. No puedo vivir sin FxCop, y tampoco puedo vivir con los warnings... supongo que hay amores que matan.&lt;/P&gt;
&lt;P&gt;Hoy he estado buscando una forma de suprimir los warnings sobre los proxies sin que al regenerarlos se borren las supresiones, y he aquí que he dado con una receta para el éxito.&lt;/P&gt;
&lt;P&gt;El truco consiste en poner las supresiones en el "GlobalSupressions.cs".&amp;nbsp;Los que uséis FxCop "a secas", podéis hacer esto de una forma bastente&amp;nbsp;sencilla... sólo hay que seleccionar el error y tras hacer click con el botón derecho, seleccionar "Copy As -&amp;gt; SuppressMessage". Por desgracia, los que tenemos el FxCop integrado en Visual Studio 2005, no tenemos esta opción (nos la han prometido para Visual Studio Orcas).&lt;/P&gt;
&lt;P&gt;No todo está perdido... todavía hay una solución. Solo, tenemos que actuar de la siguiente forma:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Suprimimos el error que ha detectado el analizador de código sobre el proxy. Esto meterá un atributo "SupressMessage" sobre el punto en el que se ha detectado el error. Nos fijamos en si el SupressMessage está sobre una clase, o sobre un método.&lt;/LI&gt;
&lt;LI&gt;Quitamos el SupressMessage del proxy, y lo copiamos en el GlobalSupressions... poniéndole como prefijo "assembly". Es decir:&lt;BR&gt;&lt;BR&gt;&lt;STRONG&gt;&lt;FONT color=#ff0000&gt;[assembly:&lt;/FONT&gt;&lt;/STRONG&gt; System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2239:ProvideDeserializationMethodsForOptionalFields")]&lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;Ahora tenemos que indicar dónde se encuentra el error original. Para eso, debemos especificar cual era el ámbito de la regla FxCop que ha saltado. Si ha saltado sobre una clase, el ámbito es "type", y si ha saltado sobre un método, es "method". Añadimos el ámbito por medio del parámetro "Scope" del atributo SuppressMessage:&lt;BR&gt;&lt;BR&gt;[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2239:ProvideDeserializationMethodsForOptionalFields", &lt;FONT color=#ff0000&gt;&lt;STRONG&gt;Scope = "type"] &lt;BR&gt;&lt;BR&gt;&lt;/STRONG&gt;&lt;/FONT&gt;&lt;FONT color=#000000&gt;o por ejemplo...&lt;BR&gt;&lt;BR&gt;[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields", &lt;FONT color=#ff0000&gt;&lt;STRONG&gt;Scope = "member"]&lt;/STRONG&gt;&lt;/FONT&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;FONT color=#000000&gt;Por último, tenemos que indicar el punto en el que se encontraba el error. Para eso, utilizaremos el parámetro de nombre "Target", en combinación con el siguiente valor:&lt;/FONT&gt;&lt;/LI&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;FONT color=#000000&gt;Si se trataba de una clase, se indica el nombre totalmente cualificado de la clase (con namespace)&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;FONT color=#000000&gt;Si se trataba de una propiedad o un miembro, el nombre totalmente cualificado del miembro.&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;FONT color=#000000&gt;Si se trataba de un método, el nombre totalmente cualificado del método, sin incluir los nombres de los argumentos (sólo los tipos) e indicando el tipo de retorno al final (con dos puntos, al estilo de C++).&lt;BR&gt;&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;FONT color=#000000&gt;Por ejemplo:&lt;BR&gt;&lt;BR&gt;&lt;/FONT&gt;[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2239:ProvideDeserializationMethodsForOptionalFields", Scope = "type", &lt;STRONG&gt;&lt;FONT color=#ff0000&gt;Target = "Sisteplant.Captor.Terminal.EventsBrokerProxy.EventInfo"&lt;/FONT&gt;&lt;/STRONG&gt;)]&lt;BR&gt;&lt;BR&gt;[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields", Scope = "member", &lt;FONT color=#ff0000&gt;&lt;STRONG&gt;Target = "Sisteplant.Captor.Terminal.WorkplaceServiceProxy.GetInManufacturingOrdersRequest.dateTime"&lt;/STRONG&gt;&lt;/FONT&gt;)]&lt;BR&gt;&lt;BR&gt;[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate", Scope = "member", &lt;FONT color=#ff0000&gt;&lt;STRONG&gt;Target = "Sisteplant.Captor.Terminal.EventsBrokerProxy.IEventsBroker.RaiseEvent(Sisteplant.Captor.Terminal.EventsBrokerProxy.EventInfo):System.Void"&lt;/STRONG&gt;&lt;/FONT&gt;)]&lt;BR&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;/UL&gt;&lt;FONT color=#000000&gt;
&lt;P&gt;&lt;BR&gt;Alguno podría tratar de suprimir varios errores tratando de establecer el Scope a "namespace"... pues bien, ni lo intentéis porque no funciona... hay que ir suprimiendo los errores uno por uno, y la lista de errores que os vais a encontrar es probablemente esta:&lt;/P&gt;
&lt;P&gt;CA1030:UseEventsWhereAppropriate&lt;BR&gt;CA1051:DoNotDeclareVisibleInstanceFields&lt;BR&gt;CA1709:IdentifiersShouldBeCasedCorrectly&lt;BR&gt;CA1711:IdentifiersShouldNotHaveIncorrectSuffix&lt;BR&gt;CA2227:CollectionPropertiesShouldBeReadOnly&lt;BR&gt;CA2239:ProvideDeserializationMethodsForOptionalFields&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;En fin, esperemos que la calidad del código generado automáticamente mejore... y no sólo haciendo que funcione el atributo "AutoGeneratedCode" que el svcutil añade a los proxies (y que por cierto, el FxCop no se toma muy en serio). Yo me pregunto... ¿tanto cuesta generar código que supere la regla CA1709?&lt;BR&gt;&lt;BR&gt;&lt;BR&gt;&lt;BR&gt;&lt;/P&gt;&lt;/FONT&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=10385" width="1" height="1"&gt;</content><author><name>gelexgaray</name><uri>http://geeks.ms/members/gelexgaray/default.aspx</uri></author><category term="WCF" scheme="http://geeks.ms/blogs/gelexgaray/archive/tags/WCF/default.aspx" /><category term="FxCop" scheme="http://geeks.ms/blogs/gelexgaray/archive/tags/FxCop/default.aspx" /></entry><entry><title>Nueva guía de optimización de Analysis Services 2005</title><link rel="alternate" type="text/html" href="/blogs/gelexgaray/archive/2007/02/05/nueva-gu-a-de-optimizaci-n-de-analysis-services-2005.aspx" /><id>/blogs/gelexgaray/archive/2007/02/05/nueva-gu-a-de-optimizaci-n-de-analysis-services-2005.aspx</id><published>2007-02-05T17:00:00Z</published><updated>2007-02-05T17:00:00Z</updated><content type="html">&lt;P&gt;Microsoft ha publicado una guía de optimización para SSAS 2005. En la guía menciona que es aplicable a partir del Service Pack 2 (que estará disponible en breve y del que hace tiempo que se puede descargar una CTP)... sin embargo, muchos de los puntos que indican son aplicables desde ahora. De momento sólo le he podido echar un vistazo rápido, pero prometo contaros mis impresiones tras una lectura detallada. Podéis descargaros la guía desde esta URL:&lt;/P&gt;
&lt;P&gt;&lt;A title=http://download.microsoft.com/download/8/5/e/85eea4fa-b3bb-4426-97d0-7f7151b2011c/SSAS2005PerfGuide.doc href="http://download.microsoft.com/download/8/5/e/85eea4fa-b3bb-4426-97d0-7f7151b2011c/SSAS2005PerfGuide.doc"&gt;http://download.microsoft.com/download/8/5/e/85eea4fa-b3bb-4426-97d0-7f7151b2011c/SSAS2005PerfGuide.doc&lt;/A&gt;&lt;/P&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=9839" width="1" height="1"&gt;</content><author><name>gelexgaray</name><uri>http://geeks.ms/members/gelexgaray/default.aspx</uri></author><category term="Analysis Services" scheme="http://geeks.ms/blogs/gelexgaray/archive/tags/Analysis+Services/default.aspx" /></entry><entry><title>Clase Singleton vs. estática</title><link rel="alternate" type="text/html" href="/blogs/gelexgaray/archive/2007/02/01/clase-singleton-vs-est_E100_tica.aspx" /><id>/blogs/gelexgaray/archive/2007/02/01/clase-singleton-vs-est_E100_tica.aspx</id><published>2007-02-01T20:28:00Z</published><updated>2007-02-01T20:28:00Z</updated><content type="html">&lt;P&gt;Esta es una duda que nos suele surgir muy a menudo a todos... ¿merece la pena desarrollar un Singleton, o me basta con una clase estática? ¿Cual es el enfoque correcto? ¿Es el Singleton la clase estática de los "pijos", o la clase estática el Singleton de los pobres? La verdad es que como siempre que hablamos de estos temas, suele haber opiniones para todos los gustos... así que contribuiré con una más a que&amp;nbsp;el mundo&amp;nbsp;sea todavía más caótico.&lt;/P&gt;
&lt;P&gt;Bueno, como todos sabéis, una clase estática y una singleton tienen, a grandes rasgos, una gran diferencia: la clase Singleton es aquella para la que existe una única instancia accesible por nuestra aplicación y la clase estática es aquella para la que ni siquiera existe instancia (todos sus métodos y miembros son estáticos). Aparentemente sirven para lo mismo, así que... ¿por qué debería usar un Singleton?&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;El principal motivo, a mi entender, es la capacidad que tiene el Singleton de evolucionar hacia una clase que tenga más de una instancia. Puede que no vemos sentido a esto, pero el principio de encapsulación que hay detrás de un Singleton es el mismo que distingue una propiedad de un miembro, o un evento de un delegado. La clase que hace un GetInstance de un Singleton asume que está obteniendo "la instancia" de esa clase, ¡pero nada nos obliga a que esa clase tenga que ser única! Es decir... ¿cúanto nos costaría ampliar el código que os pongo abajo, para añadirle un contador de instancias y permitir un máximo de tres? (lo dejo como ejercicio espiritual para&amp;nbsp;mentes ávidas de pensar). En resumen... un puntito para el Singleton.&lt;BR&gt;
&lt;DIV class=CodeFormatContainer&gt;
&lt;DIV class=csharpcode&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;class&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#2b91af size=2&gt;Singleton&lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;{&lt;/P&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;&amp;nbsp;&amp;nbsp; private&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;static&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#2b91af size=2&gt;Singleton&lt;/FONT&gt;&lt;FONT size=2&gt; _instance;&lt;/P&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;&amp;nbsp;&amp;nbsp; private&lt;/FONT&gt;&lt;FONT size=2&gt; Singleton() &lt;BR&gt;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp; }&lt;/P&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;&amp;nbsp;&amp;nbsp; public&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;static&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#2b91af size=2&gt;Singleton&lt;/FONT&gt;&lt;FONT size=2&gt; Instance&lt;BR&gt;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;get&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/FONT&gt;&lt;FONT size=2&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;if&lt;/FONT&gt;&lt;FONT size=2&gt; (_instance == &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;null&lt;/FONT&gt;&lt;FONT size=2&gt;)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _instance = &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;new&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#2b91af size=2&gt;Singleton&lt;/FONT&gt;&lt;FONT size=2&gt;();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;return&lt;/FONT&gt;&lt;FONT size=2&gt; _instance;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp; &lt;/FONT&gt;&lt;FONT size=2&gt;}&lt;BR&gt;}&lt;/P&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/LI&gt;&lt;/FONT&gt;&lt;/UL&gt;
&lt;UL&gt;
&lt;LI&gt;Otra ventaja del Singleton está en que los métodos no son estáticos, y por tanto se pueden sobreescribir en las clases herederas (son "overrideables"). No se puede hacer un override de un método estático. Vamos, que si pretendemos hacer una jerarquía de clases de instancia única, más nos vale que tiremos hacia el singleton... de lo contrario tendremos problemas. Singleton 2, Estática 0&lt;/LI&gt;
&lt;LI&gt;La clase Singleton tiene instancia, y eso en sí ya es una ventaja. Por ejemplo, eso nos facilitará que nuestro Singleton pueda implementar interfaces que sencillamente una clase estática nunca podrá implementar. De nuevo, la clase Singleton puede "crecer" con más facilidad que la estática en este sentido. Singleton 3, Estática 0&lt;/LI&gt;
&lt;LI&gt;En cuanto a qué es mejor para implementar una clase Thread Safe, fijaros que básicamente el problema que tenemos es el mismo: si tenemos varios threads modificando miembros de la clase, habrá que sincronizarlos y asegurarnos de que sólo uno es capaz de alterar un miembro cada vez. La clase Singleton tiene una peguilla adicional, y es que tenemos que proteger también el método que obtiene la instancia.&amp;nbsp;No es un gran problema... hay un artículo muy interesante de cómo hacerlo &lt;A href="http://www.yoda.arachsys.com/csharp/singleton.html"&gt;AQUÍ&lt;/A&gt;. Yo diría que en cuanto a la seguridad de threads, ambas clases "empatan".&lt;/LI&gt;
&lt;LI&gt;Algunos opinan que la clase Singleton es más adecuada para representar clases que mantienen un estado. En realidad esta puede ser más una cuestión de gusto (buen gusto, se entiende) que un requisito real. Ambas clases pueden contener perfectamente un estado. De nuevo otro empate.&lt;/LI&gt;
&lt;LI&gt;¿Y dónde gana la clase estática? En su simplicidad. Así que como el "Keep it Simple" es un argumento que vale por tres, ¡digamos que Singleton y clase estática empatan a puntos! Singleton 3, Estática 3&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Vamos, que la idea con la que nos debemos quedar es que una clase Singleton va a hacer nuestro programa un pelín más difícil de comprender, así que como todo, es un recurso que sólo debemos utilizar si es necesario. Y yo, como siempre, que sigo sin mojarme... ¿quieres mojarte tú? ¡¡pues mándame tus comentarios!! Los espero ansioso.&lt;/P&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=9623" width="1" height="1"&gt;</content><author><name>gelexgaray</name><uri>http://geeks.ms/members/gelexgaray/default.aspx</uri></author><category term="Dise&amp;#241;o y patrones" scheme="http://geeks.ms/blogs/gelexgaray/archive/tags/Dise_26002300_241_3B00_o+y+patrones/default.aspx" /></entry><entry><title>El verdadero geek no se queja de que su reproductor de MP3 no ordene las canciones...</title><link rel="alternate" type="text/html" href="/blogs/gelexgaray/archive/2007/01/23/el-verdadero-geek-no-se-queja-de-que-su-reproductor-de-mp3-no-ordene-las-canciones.aspx" /><id>/blogs/gelexgaray/archive/2007/01/23/el-verdadero-geek-no-se-queja-de-que-su-reproductor-de-mp3-no-ordene-las-canciones.aspx</id><published>2007-01-23T20:22:00Z</published><updated>2007-01-23T20:22:00Z</updated><content type="html">&lt;P&gt;... el verdadeo geek, escribe una rutina que ordene alfabéticamente los archivos y directorios de un directorio FAT. &lt;/P&gt;
&lt;P&gt;Sí, lo reconozco: tengo un reproductor de MP3 que es una verdadera porquería. Antes tenía un Creative MuVO V200, pero desde que me lo cargué con una actualización de firmware, mi vida se había vuelto gris y anodina. Sabía que si me compraba algo mejor que el MuVO, también acabaría tratando de "tunearlo" a toda costa, y por ende, cargándomelo, así que me decanté por un modelo baratito. Así, al menos, cuando me lo cargase, tampoco me daría demasiada pena.&lt;/P&gt;
&lt;P&gt;El caso es que mi nuevo reproductor desde el principio me dejó desconcertado. Resulta que cuando cargaba canciones desde el Windows Media Player, estas no se reproducían en orden alfabético, sino en el orden en el que las había añadido al reproductor. ¡Qué invento del demonio! &lt;/P&gt;
&lt;P&gt;&amp;lt;&amp;lt; Tanto esmero en ordenar mi biblioteca de emepetreses para que este chisme con vida propia decida que mi vida requiere un orden distinto al que yo he previsto. No me gusta... no, no, no y no. Me niego a la regir mi vida al ritmo de un tirano digital &amp;gt;&amp;gt;. Tenía que hacer algo, así que busqué una explicación a semejante ultraje.&lt;/P&gt;
&lt;P&gt;Lo primero que pensé fue: "el ceporro que haya programado esto, ordena las canciones por fecha de creación del archivo". Es curioso... los programadores siempre pensamos que el resto de programadores son unos ceporros, ¿verdad? Y resulta que no es ni más ni menos certero que el nivel ceporrismo que tú, querido lector, puedas intuir en mis palabras.&amp;nbsp;Lo cierto del caso es que el programador del firmware de mi MP3 no es un ceporro. Es un programador ágil, que no ha implementado ninguna característica porque nadie se la ha solicitado.&lt;/P&gt;
&lt;P&gt;El problema de mi reproductor de MP3 es muy común, y no está causado por la mala baba de un programador que quiera dominar el mundo imponiendo su propio orden a nuestros archivos: está causado por la implementación del sistema de archivos FAT.&lt;/P&gt;
&lt;P&gt;Pensemos en cómo es un directorio FAT:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://geeks.ms/blogs/gelexgaray/WindowsLiveWriter/Elverdaderogeeknosequejadequesureproduc_1279E/escanear0004%5B2%5D.jpg"&gt;&lt;IMG style="BORDER-RIGHT:0px;BORDER-TOP:0px;BORDER-LEFT:0px;BORDER-BOTTOM:0px;" height=274 src="http://geeks.ms/blogs/gelexgaray/WindowsLiveWriter/Elverdaderogeeknosequejadequesureproduc_1279E/escanear0004_thumb.jpg" width=640 border=0&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;Bueno, además de ver que soy un cutre que dibuja en las servilletas de papel, vemos que un directorio es una simple tabla con el nombre, extensión, atributos... y un apuntador al primer cluster en el que se encuentra el archivo. ¿Cual es el problema con mi reproductor de MP3? El problema es que cuando añadimos archivos o subdirectorios a un volumen FAT, estamos añadiendo secuencialmente entradas a esta tabla. El programador de mi reproductor, va leyendo y reproduciendo cada una de estas entradas, así que si las pilla desordenadas, las reproduce tal cual (provocando la ira de los que como a mi, nos gusta oir las canciones en un determinado orden).&lt;/P&gt;
&lt;P&gt;¿Cómo se puede solucionar esto?&lt;/P&gt;
&lt;P&gt;Lo primero que se nos ocurre es: ¡Ordenemos esa tabla! Se trata sólo de leer estructuras de tamaño fijo desde disco a un buffer, ordenarlas, y volver a volcarlas a disco. Es cierto, el problema es tan sencillo como ese... pero este enfoque tiene dos desventajas:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Requiere acceso directo a disco, por lo que en Windows sólo podría funcionar con permisos de administrador.&lt;/LI&gt;
&lt;LI&gt;Las estructuras a manejar son distintas en función del tipo de FAT que tenga el disco (hay FAT12, 16 y 32, con ligeras diferencias en el directorio... nombres largos... etc).&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;La segunda solución requiere aprovecharse del conocimiento de la mente de los programadores. Sí amigos... pensad en cómo MOVERÍAIS archivos en un directorio FAT. Desde luego, a nadie se le ocurriría moverlos físicamente en disco... ¡basta con cambiar las entradas de la tabla!. Así que ese es el truco que siempre funciona para ordenar archivos en un volumen FAT: ir moviéndolos a un nuevo directorio, sabiendo que la nueva tabla se irá creando secuencialmente. Una vez completada la operación, sólo tenemos que sustituir el directorio original por el nuevo.&lt;/P&gt;
&lt;P&gt;Así que ahora ya puedo ir tranquilamente por el mundo, escuchando mis canciones en el orden que a mi me gusta, y mirando por encima del hombro a todo aquel que tiene un iPod, Muvo, Zune, o cualquier reproductor de "pedigree". Vosotros tendréis un reproductor mejor que el mío, pero el mío venía con rompecabezas de regalo, ¡y lo he solucionado!.&lt;/P&gt;
&lt;P&gt;PD: Os dejo los fuentes y binarios del programita que uso para ordenar el directorio de mi reproductor de MP3. A ver si alguien le pone una bonita interfaz gráfica de usuario, lo modifica para que ordene por distintos criterios al alfabético, ¡y de paso me lo envía de vuelta!&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;A href="http://geeks.ms/files/folders/gelexgaray/entry9122.aspx" target=_blank&gt;DirSort.zip&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://geeks.ms/files/folders/gelexgaray/entry9123.aspx" target=_blank&gt;DirSort-source.zip&lt;/A&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=9121" width="1" height="1"&gt;</content><author><name>gelexgaray</name><uri>http://geeks.ms/members/gelexgaray/default.aspx</uri></author><category term="Ideas Geek" scheme="http://geeks.ms/blogs/gelexgaray/archive/tags/Ideas+Geek/default.aspx" /></entry><entry><title>Transacciones en Integration Services</title><link rel="alternate" type="text/html" href="/blogs/gelexgaray/archive/2006/12/19/transacciones-en-integration-services.aspx" /><id>/blogs/gelexgaray/archive/2006/12/19/transacciones-en-integration-services.aspx</id><published>2006-12-19T19:49:00Z</published><updated>2006-12-19T19:49:00Z</updated><content type="html">&lt;P&gt;Uno de los puntos de SSIS que muchas veces nos pasa desapercibido y que sin embargo conviene conocer, utilizar y amar, es el soporte para transacciones. Estamos cargando un DataMart, y ¡zas! la carga falla a mitad de camino. ¿Qué hacemos? ¿Parece mentira que la ejecución de un ETL que puede hacer infinidad de cambios en nuestro DataMart&amp;nbsp;se pueda deshacer en caso de fallo, verdad? ¡Pues se puede!&lt;/P&gt;
&lt;P&gt;Para controlar las transacciones, todos los objetos del "Control Flow" (incluido el propio control flow)&amp;nbsp;tienen una propiedad llamada "TransactionOption", que puede tomar los siguientes valores:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;Required&lt;/STRONG&gt;:&amp;nbsp;Este elemento se ejecuta en el contexto de una nueva transacción.&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Supported&lt;/STRONG&gt;: El elemento se ejecuta en el contexto de la transacción que ya estuviese abierta (por alguno de sus "padres"). En caso de que no se hubiese iniciado ninguna transacción, el objeto no es transaccional. Es el valor por defecto que da Integration Services a todos los elementos del flujo de control.&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;NotSupported&lt;/STRONG&gt;: El objeto no es transaccional, aunque esté ejecutándose en el contexto de una transacción&lt;/LI&gt;&lt;/UL&gt;
&lt;BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;A href="http://geeks.ms/photos/gelexgaray/images/7710/original.aspx" target=_blank&gt;&lt;IMG src="http://geeks.ms/photos/gelexgaray/images/7710/original.aspx" border=0&gt;&lt;/A&gt;&amp;nbsp;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Entonces, hacer un ETL transaccional es tan sencillo como pulsar en el fondo del "Control Flow" de un paquete y establecer TransactionLevel a "Required". Eso hará que todos los elementos que arrastremos al flujo se ejecuten por defecto en el contexto de una transacción. Si uno de estos elementos falla, se desharán los cambios realizados por el resto de elementos que se hubiesen ejecutado dentro de la misma transacción.&lt;/P&gt;
&lt;P&gt;El segundo parámetro a tener en cuenta es IsolationLevel, que especifica cómo gestionará SSIS la transacción. Podéis buscar información en MSDN sobre este parámetro... yo sólo os dejo caer un par de notas:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Cuanto menos restrictivo sea el modo de funcionamiento de la transacción, mayor será el rendimiento. Por ejemplo, ReadUncommited y Chaos permiten ver los cambios antes de que estos se hagan permanentes con un Commit. O sea, que si estamos cargando un DataMart y mientras tanto alguien accede al mismo, obtendrá datos inconsistentes. Si nuestras circunstancias permiten "evitar" el acceso al DataMart mientras esté siendo cargado, puede ser una buena opción.&lt;/LI&gt;
&lt;LI&gt;Serializable es el más restrictivo, pero a la vez más seguro: evita que se pueda acceder a los datos nuevos que insertemos en el DataMart hasta que se haga un Commit, y evita que se&amp;nbsp;modifiquen&amp;nbsp;los datos anteriores al inicio de la transacción. Generalmente es el más adecuado para cargar un DataMart (es la opción por&amp;nbsp;defecto).&amp;nbsp;&lt;/LI&gt;
&lt;LI&gt;Snapshot es nuevo en SQL Server 2005, y permite trabajar a la transacción sobre una "copia" de los datos tal y como estaban al inicio de la transacción, sin bloquearlos. Al finalizar la transacción, se consolidan los cambios. Esta es la que menos impacto supondrá en el resto de aplicaciones que accedan al DataMart mientras lo estamos cargando, pero a costa de usar parte de nuestro espacio de almacenamiento. Personalmente no le veo demasiado uso en la carga de un DataMart, porque por su propia naturaleza, los datos del DataMart no suelen sufrir modificaciones (por lo que Serializable puede ser una mejor opción)&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Espero que después de esto en vuestras oficinas dejen de oirse gritos y lamentos debido a ese corte de luz que sucede siempre justo en medio de la ejecución de un ETL...&lt;/P&gt;
&lt;P&gt;Y ya sabés, feliz navidad.... ¡y prósperas transformaciones!&lt;/P&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=7712" width="1" height="1"&gt;</content><author><name>gelexgaray</name><uri>http://geeks.ms/members/gelexgaray/default.aspx</uri></author><category term="Integration Services" scheme="http://geeks.ms/blogs/gelexgaray/archive/tags/Integration+Services/default.aspx" /></entry><entry><title>¿Te gusta mi Software Factory?</title><link rel="alternate" type="text/html" href="/blogs/gelexgaray/archive/2006/12/06/te-gusta-mi-software-factory.aspx" /><id>/blogs/gelexgaray/archive/2006/12/06/te-gusta-mi-software-factory.aspx</id><published>2006-12-06T11:54:00Z</published><updated>2006-12-06T11:54:00Z</updated><content type="html">&lt;P&gt;Hay dos cosas que me pierden: el merchandising de los eventos de Microsoft, y casi todo lo nuevo que voy probando. Sí, si, lo se... soy un poco "pattern happy", un poco amante de los gadgets y muy, muy "friki" (en el sentido más puramente hispano de la palabra). Actualmente me está atrayendo poderosamente la idea de las Software Factories y los Domain Specific Languajes (DSL). Me atrae tan poderosamente que, como me conozco, empiezo a dudar sobre si lo que me atrae es real, o son cantos de sirena.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;¿Software factoqué?&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Cuando el famoso cocinero de la tele nos prepara un delicioso Marmitako, o nos deleita con una chuletitas de cordero ricas, ricas, ricas... nos está enseñando una receta. Nos da un conjunto de pasos, técnicas y conocimientos, que nos ayudan a triunfar en un determinado dominio: la cocina. Digamos que la distancia para sorprender a nuestra churri, es más corta si seguimos una receta que si tratamos de improvisar en los fogones.&lt;/P&gt;
&lt;P&gt;Una Software Factory sigue el mismo principio: es un conjunto de patrones, documentación (recetas), plantillas y mucha, mucha, mucha... ¡generación automática de código! Personalmente estoy usando la &lt;A href="http://practices.gotdotnet.com/projects/scbat"&gt;Smart Client Software Factory&lt;/A&gt;, que te ayuda a desarrollar Smart Clients que se sustentan sobre &lt;A href="http://practices.gotdotnet.com/projects/cab"&gt;Composite UI Application Block (CAB)&lt;/A&gt;. &lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Vale, eso tiene sentido... ¿y los DSL?&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Las Software Factory casi siempre van de la mano de los DSL, o "Domain Specific Languajes". ¿Te imaginas que el programa de Arguiñano se hiciese en el plató de Bricomanía? ¿Sería raro, verdad? Cada situación requiere un conjunto distinto de herramientas, y cada dominio, un lenguaje adaptado a su contexto. El problema de los lenguajes de propósito general, es que son como el plató de Bricomanía... por el simple hecho de que tengamos una sierra de calar, podemos sentir la tentación de usarla para trinchar el pavo. La solución para evitar el error,&amp;nbsp;es deshacerse de la sierra de calar.&lt;/P&gt;
&lt;P&gt;Hace poco, alguien, tratando de hacerme bajar de mi nube, me decía que hace 20 años que tratan de vendernos los lenguajes de 4ª generación, y me insinuaba que esto es el mismo perro con distinto collar. Bueno, en cierto modo los DSL se parecen a los 4GL en que buscan ser declarativos (yo digo lo que quiero, y no cómo lo quiero) pero no pretenden ser tan ambiciosos. Ciñéndose a un dominio, es más fácil tener éxito con un lenguaje declarativo.&lt;/P&gt;
&lt;P&gt;Lo cierto es que cada vez que abrimos el diseñador de interfaces de Visual Studio, ya estamos usando un DSL. Nosotros añadimos controles a un formulario&amp;nbsp;y enlazamos eventos con código usando un lenguaje visual, basado en el paradigma de arrastrar y soltar. Lo mismo ocurre cuando desarrollamos un ETL con Integration Services... los DSL llevan años acompañándonos. &lt;/P&gt;
&lt;P&gt;En algunos casos, el DSL ni siquiera requiere que se abandone el lenguaje de propósito general... simplemente, se limita a ocultar la complejidad del mismo, y nos guía para que sólo utilicemos aquella parte del lenguaje adecuada a nuestros fines. Llevamos años encapsulando para tratar de ocultar la complejidad... ¿por qué somos tan reacios a que una herramienta nos abstraiga del propio lenguaje procedural?&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Lo pasamos por la batidora, y directo al horno (220ºC)&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Microsoft nos está preparando un buen plato&amp;nbsp;a base de DSLs, patrones, Software Factories y demás ingredientes. Los muchachos se llaman &lt;A href="http://msdn.microsoft.com/vstudio/teamsystem/workshop/gat/download.aspx"&gt;GAX, GAT (Guided Automation Extensions y Guided Application Toolkit, respectivamente)&lt;/A&gt;&amp;nbsp;y &lt;A href="http://msdn.microsoft.com/vstudio/DSLTools/"&gt;DSLTools&lt;/A&gt;&amp;nbsp;y están a punto de llegar a este lado del Mississippi.&lt;/P&gt;
&lt;P&gt;Esta pretende ser una revolución en la forma en la que desarrollamos software. Paremonos a pensar en la mayoría de ISVs y sus catálogos de software... es habitual que los ISV se especialicen en un dominio, ¿verdad? Los hay quienes hacen herramientas de desarrollo, software de tratamiento de imágenes, productos de seguridad... pero generalmente, igual que cada cabra tira a su monte, cada ISV va a su terreno. Luego hay consultoras capaces de hacer de todo (hasta botijos, si estuviesen bien pagados), pero bueno, estamos hablando de desarrollo de software, y no de tratantes de carne humana (huy lo que he dichoooooo...), y estoy seguro que hasta éstas pueden beneficiarse de las Software Factories.&lt;/P&gt;
&lt;P&gt;Imaginaos este mundo idílico, en el que nuestro arquitecto desarrolla la Software Factory adecuada a nuestro dominio, y nuestros desarrolladores la utilizan para programar aplicaciones específicas para el dominio. ¿Acaso no es una forma estupenda de transferir el conocimiento?&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;¡Camarero una manzanilla!&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Para acabar sin indigestión, os voy a recetar un poco de descanso (a poder ser en vuestro sofá más cómodo) y cuando vuestro cerebro pida guerra, unos cuantos links:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;A title=http://blogs.msdn.com/tomholl/ href="http://blogs.msdn.com/tomholl/"&gt;&lt;A href="http://blogs.msdn.com/tomholl/default.aspx"&gt;Tom Hollander's blog&lt;/A&gt;:&lt;/A&gt; Habla mucho sobre GAT y GAX, y también da noticias sobre nuevos "application blocks"&lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://staff.southworks.net/blogs/matiaswoloski/default.aspx"&gt;Matias Woloski&lt;/A&gt;: Sobre todo habla de la Smart Client Software Factory&lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://msdn.microsoft.com/practices/topics/SoftwareFactories/default.aspx"&gt;Patterns &amp;amp; Practices: Software Factories&lt;/A&gt;: Noticias sobre las software factories de Microsoft.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Y ahora, ya puedes opinar... ¿Estamos hablando de la Piedra Rossetta del desarrollo de software, o son cantos de sirena?&lt;/P&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=7243" width="1" height="1"&gt;</content><author><name>gelexgaray</name><uri>http://geeks.ms/members/gelexgaray/default.aspx</uri></author><category term="Opini&amp;#243;n" scheme="http://geeks.ms/blogs/gelexgaray/archive/tags/Opini_26002300_243_3B00_n/default.aspx" /><category term="Software Factories" scheme="http://geeks.ms/blogs/gelexgaray/archive/tags/Software+Factories/default.aspx" /></entry><entry><title>Ya tenemos RadarCube NET Windows Forms for Microsoft Analysis Services </title><link rel="alternate" type="text/html" href="/blogs/gelexgaray/archive/2006/11/28/ya-tenemos-radarcube-net-windows-forms-for-microsoft-analysis-services.aspx" /><id>/blogs/gelexgaray/archive/2006/11/28/ya-tenemos-radarcube-net-windows-forms-for-microsoft-analysis-services.aspx</id><published>2006-11-28T19:59:00Z</published><updated>2006-11-28T19:59:00Z</updated><content type="html">&lt;P&gt;El mercado de los controles del tipo "pivot table" empieza a activarse. Señores... hay demanda para un sustituto de los Office Web Controls, y RadarSoft está echando el resto. Hoy han lanzado RadarCube NET Windows Forms, un control Winforms para .NET 2.0 que permite presentar datos multidimensionales en nuestras aplicaciones Windows. Podéis encontrar más información y unos cuantos pantallazos en esta URL: &lt;A href="http://www.radar-soft.com/products/radarwin_msas.aspx"&gt;http://www.radar-soft.com/products/radarwin_msas.aspx&lt;/A&gt;. &lt;/P&gt;
&lt;P&gt;Además hoy han anunciado que bajan los precios del &lt;A class="" title="RadarCube for Analysis Services (o cómo el ratón a veces rinde más que el puma)" href="http://geeks.ms/blogs/gelexgaray/archive/2006/11/07/RadarCube-for-Analysis-Services-_2800_o-c_F300_mo-el-rat_F300_n-a-veces-rinde-m_E100_s-que-el-puma_2900_.aspx" target=_blank&gt;RadarCube ASP.NET&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;Dos estupendas noticias... a ver si hay suerte y se empiezan a popularizar herramientas que hasta ahora estaban reservadas&amp;nbsp;sólo a una élite. Como diría Groucho... ¡¡¡Más madera!!!&lt;/P&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=6844" width="1" height="1"&gt;</content><author><name>gelexgaray</name><uri>http://geeks.ms/members/gelexgaray/default.aspx</uri></author><category term="Visores OLAP" scheme="http://geeks.ms/blogs/gelexgaray/archive/tags/Visores+OLAP/default.aspx" /></entry><entry><title>Testeo unitario de cubos OLAP</title><link rel="alternate" type="text/html" href="/blogs/gelexgaray/archive/2006/11/20/_BF00_C_F300_mo-testeo-mis-cubos-OLAP-o-mi-ETL_3F00_.aspx" /><link rel="enclosure" type="application/x-zip-compressed" length="11947" href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Components.PostAttachments/00.00.00.56.89/AdventureWorksOLAPTestProject.zip" /><id>/blogs/gelexgaray/archive/2006/11/20/_BF00_C_F300_mo-testeo-mis-cubos-OLAP-o-mi-ETL_3F00_.aspx</id><published>2006-11-20T19:01:00Z</published><updated>2006-11-20T19:01:00Z</updated><content type="html">&lt;P&gt;En Internet no se encuentran muchas páginas sobre cómo testear un cubo OLAP... probablemente, como en toda tecnología "emergente", cada uno se las arregle como pueda y pocas cosas estén ampliamente extendidas. Sin embargo, con el resto de tecnologías "más convencionales" todo el mundo tiene una opinión formada sobre el testeo unitario o el "test driven development" (generalmente para bien). ¿Se pueden conciliar ambos terminos? ¿Puedo escribir "unit tests" para mis cubos OLAP?&lt;/P&gt;
&lt;P&gt;La respuesta es "SIN DUDA". El mundo del Business Intelligence puede beneficiarse en gran manera del testeo unitario, gracias a lo que se conoce como "Data Driven Unit Test". ¿De qué va esto?&lt;/P&gt;
&lt;P&gt;Analicemos las siguientes sentencias SQL y MDX, lanzadas respectivamente contra la base de datos "Adventure Works" y el cubo de Analysis Services correspondiente:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT color=#0000ff&gt;SELECT&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;/FONT&gt;Production&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;.&lt;/FONT&gt;&lt;FONT size=2&gt;Product&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;.&lt;/FONT&gt;&lt;FONT size=2&gt;ProductNumber &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;AS&lt;/FONT&gt;&lt;FONT size=2&gt; Product&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt;&amp;nbsp;&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#ff00ff size=2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SUM&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT size=2&gt;Sales&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;.&lt;/FONT&gt;&lt;FONT size=2&gt;SalesOrderDetail&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;.&lt;/FONT&gt;&lt;FONT size=2&gt;OrderQty&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;)&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;AS&lt;/FONT&gt;&lt;FONT size=2&gt; Quantity&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;FROM&lt;/FONT&gt;&lt;FONT size=2&gt; Sales&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;.&lt;/FONT&gt;&lt;FONT size=2&gt;SalesOrderDetail&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt; Production&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;.&lt;/FONT&gt;&lt;FONT size=2&gt;Product&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;WHERE&lt;/FONT&gt;&lt;FONT size=2&gt; Sales&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;.&lt;/FONT&gt;&lt;FONT size=2&gt;SalesOrderDetail&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;.&lt;/FONT&gt;&lt;FONT size=2&gt;ProductID &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;=&lt;/FONT&gt;&lt;FONT size=2&gt; Production&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;.&lt;/FONT&gt;&lt;FONT size=2&gt;Product&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;.&lt;/FONT&gt;&lt;FONT size=2&gt;ProductID&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;GROUP&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;BY&lt;/FONT&gt;&lt;FONT size=2&gt; Production&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;.&lt;/FONT&gt;&lt;FONT size=2&gt;Product&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;.&lt;/FONT&gt;&lt;FONT size=2&gt;ProductNumber&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;ORDER&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;BY&lt;/FONT&gt;&lt;FONT size=2&gt; Product &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;ASC&lt;/FONT&gt;&lt;/P&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;FONT color=#0000ff size=2&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;SELECT&lt;FONT color=#000000 size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;NON&lt;/FONT&gt;&lt;FONT color=#000000 size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;EMPTY&lt;/FONT&gt;&lt;FONT color=#000000 size=2&gt; [Product].[Product Key].[Product Key] &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;ON&lt;/FONT&gt;&lt;FONT color=#000000 size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;ROWS&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT color=#000000&gt;,&lt;BR&gt;&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;FONT color=#000000&gt;[Measures].[Order Quantity]&lt;/FONT&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;ON&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;COLUMNS&lt;BR&gt;FROM&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT color=#000000&gt; [Adventure Works]&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;P&gt;&lt;FONT color=#000000&gt;Si las ejecutamos, ambas producen resultados similares... una sobre el sistema OLTP y la otra sobre el sistema OLAP. Vaya, empezamos a entender... ¡si ambos sistemas producen resultados similares, eso debe significar que nuestro sistema OLAP funciona correctamente! Eso es el Data Driven Unit Testing, y nos vendrá de miedo para probar nuestros cubos. Recordemos que el escenario&amp;nbsp;habitual en un desarrollo de BI será partir de un sistema existente, así que... ¿qué mejor prueba de que nuestro sistema funciona, que demostrar que&amp;nbsp;devuelve los mismos&amp;nbsp;resultados que el sistema de partida?. Cuantos más cruces de dimensiones comparemos con salidas del sistema OLTP, mejor será nuestra batería de tests.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#000000&gt;Es difícil, por no decir imposible, tener una cobertura del 100% del cubo, pero como se suele decir, testear algo es infinitamente mejor que no testear.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#000000&gt;&lt;STRONG&gt;Data Driven Unit Test&amp;nbsp;en Visual Studio Team System&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#000000&gt;Para realizar testeo unitario guiado por datos, tenemos que partir de una tabla de base de datos en la que tendremos almacenado cada uno de nuestros juegos de pruebas. En el ejemplo que he puesto, si no disponemos de tabla, tendremos que crear una vista.&lt;/FONT&gt;&lt;/P&gt;&lt;FONT color=#0000ff size=2&gt;
&lt;UL&gt;
&lt;LI&gt;CREATE&lt;/FONT&gt;&lt;FONT color=#000000 size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;VIEW&lt;/FONT&gt;&lt;FONT color=#000000 size=2&gt; Test&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;.&lt;/FONT&gt;&lt;FONT color=#000000 size=2&gt;vOrderQuantityPerProductKey &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;AS&lt;BR&gt;SELECT&lt;/FONT&gt;&lt;FONT color=#000000 size=2&gt; Production&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;.&lt;/FONT&gt;&lt;FONT color=#000000 size=2&gt;Product&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;.&lt;/FONT&gt;&lt;FONT color=#000000 size=2&gt;ProductNumber &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;AS&lt;/FONT&gt;&lt;FONT color=#000000 size=2&gt; Product&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT color=#000000&gt; &lt;BR&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT color=#ff00ff size=2&gt;SUM&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;(&lt;/FONT&gt;&lt;FONT size=2&gt;Sales&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;.&lt;/FONT&gt;&lt;FONT size=2&gt;SalesOrderDetail&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;.&lt;/FONT&gt;&lt;FONT size=2&gt;OrderQty&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;)&lt;/FONT&gt;&lt;FONT size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;AS&lt;/FONT&gt;&lt;FONT size=2&gt; Quantity&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;FROM&lt;/FONT&gt;&lt;FONT color=#000000 size=2&gt; Sales&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;.&lt;/FONT&gt;&lt;FONT color=#000000 size=2&gt;SalesOrderDetail&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;,&lt;/FONT&gt;&lt;FONT color=#000000 size=2&gt; Production&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;.&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT color=#000000&gt;Product&lt;BR&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;WHERE&lt;/FONT&gt;&lt;FONT color=#000000 size=2&gt; Sales&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;.&lt;/FONT&gt;&lt;FONT color=#000000 size=2&gt;SalesOrderDetail&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;.&lt;/FONT&gt;&lt;FONT color=#000000 size=2&gt;ProductID &lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;=&lt;/FONT&gt;&lt;FONT color=#000000 size=2&gt; Production&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;.&lt;/FONT&gt;&lt;FONT color=#000000 size=2&gt;Product&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;.&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT color=#000000&gt;ProductID&lt;BR&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;GROUP&lt;/FONT&gt;&lt;FONT color=#000000 size=2&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=2&gt;BY&lt;/FONT&gt;&lt;FONT color=#000000 size=2&gt; Production&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;.&lt;/FONT&gt;&lt;FONT color=#000000 size=2&gt;Product&lt;/FONT&gt;&lt;FONT color=#808080 size=2&gt;.&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;FONT color=#000000&gt;ProductNumber&lt;/FONT&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT color=#000000&gt;Este es el punto que menos me gusta, tener que partir obligatoriamente de una tabla accedida mediante OleDB y no poder partir de una sentencia SQL... pero bueno, sigamos a lo nuestro. Nos ponemos las botas de programar, nuestra música favorita, y creamos un nuevo proyecto de tipo "Test Project".&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;A href="http://geeks.ms/photos/gelexgaray/images/6579/original.aspx" target=_blank&gt;&lt;IMG src="http://geeks.ms/photos/gelexgaray/images/6579/640x459.aspx" border=0&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#000000&gt;Visual Studio creará por nosotros una clase de test, con un método de test. Tendremos que indicar que el método de test es "Data Driven", para eso, editamos las propiedades del test e indicamos:&lt;/FONT&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;FONT color=#000000&gt;&lt;U&gt;Data Connection String&lt;/U&gt;: Cadena de conexión a nuestra base de datos.&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;FONT color=#000000&gt;&lt;U&gt;Data Table Name&lt;/U&gt;: El nombre de la tabla donde se encuentran los valores a probar, junto con los resultados esperados.&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;FONT color=#000000&gt;&lt;U&gt;Data Access Method&lt;/U&gt;: Squential. Con esto indicamos que se deberá probar secuencialmente con todos y cada uno de los valores de la tabla.&lt;/FONT&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT color=#000000&gt;&lt;A href="http://geeks.ms/photos/gelexgaray/images/6618/original.aspx" target=_blank&gt;&lt;IMG src="http://geeks.ms/photos/gelexgaray/images/6618/317x413.aspx" border=0&gt;&lt;/A&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT color=#000000&gt;Como resultado de la edición de estas tres propiedades, Visual Studio decorará nuestro método de test con un atributo DataSource, señal clara de que nuestro test es guiado por datos.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; [DataSource("System.Data.SqlClient", &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; "Data Source=.;Initial Catalog=AdventureWorks;Integrated Security=True", &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; "Test.vOrderQuantityPerProductKey", &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; DataAccessMethod.Sequential),&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; TestMethod()]&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#000000&gt;&lt;STRONG&gt;Rematando la faena: escritura del test&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#000000&gt;Escribir el test unitario es sencillo... lo primero que tenemos que hacer es tener una propiedad de tipo TestContext, llamada TestContext. En esta propiedad, Visual Studio nos irá dejando el contexto de cada test, es decir, en nuestro caso, los valores para cada uno de los juegos de prueba.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="courier new,courier"&gt;&lt;FONT color=#000000&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/FONT&gt;private TestContext _myTestContext;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="courier new,courier"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public TestContext TestContext&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get { return _myTestContext; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; set { _myTestContext = value; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#000000&gt;Lo siguiente es escribir el test:&lt;/FONT&gt;&lt;/P&gt;&lt;FONT face="courier new,courier"&gt;
&lt;P&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void OrderQuantityPerProductKeyTestMethod()&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Construimos la sentencia MDX para el producto actual, y obtenemos la cantidad del cubo.&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; String mdxQuery = "SELECT [Measures].[Order Quantity] ON COLUMNS&amp;nbsp;"&amp;nbsp;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;+ "FROM [Adventure Works] WHERE [Product].[Product Key].["&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; + TestContext.DataRow["Product"]&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; + "]";&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; AdomdCommand mdxQueryCommand = new AdomdCommand(mdxQuery, _adomdConnection);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; CellSet cubeResult = mdxQueryCommand.ExecuteCellSet();&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="courier new,courier"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Comparamos el resultado del cubo, con el resultado de la base de datos.&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; int result = (int)cubeResult.Cells[0].Value;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; int expected = (int)TestContext.DataRow["Quantity"];&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.AreEqual(expected, result, 16);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="courier new,courier"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/FONT&gt;&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;Como veis, me limito a ejecutar una sentencia MDX que me devuelva de los cubos OLAP el valor equivalente al del juego de ensayo. Para obtener el juego de ensayo, leo del diccionario "DataRow" del TestContext cada una de las columnas de mi tabla de pruebas, y por último pruebo con un Assert que los resultados del cubo sean los esperados.&lt;/P&gt;
&lt;P&gt;La invocación de Assert.AreEqual tiene un tercer parámetro que vale 16... ¿qué significa?&lt;/P&gt;
&lt;P&gt;Este parámetro, es el "delta" de la función. Muchas veces, cuando metemos datos en un cubo por medio de un ETL, durante el proceso de limpieza se pierde precisión en los datos. Como resultado de la limpieza, los valores extraidos de la base de datos OLTP y OLAP podrían no coincidir... pues bien, el "delta", es la desviación que toleraremos en nuestra prueba (en este caso, +/- 16 enteros). Podéis descargaros el proyecto completo que he adjuntado a este post, y experimentar todo lo que queráis (por ejemplo, probad a bajar el valor del delta y observad qué pasa...).&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Despidiendo el post&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Hemos visto cómo los test unitarios no están de más en el mundo de la inteligencia de negocios... y recordad que tal y cómo dice SCRUM, un proyecto no está terminado mientras no esté probado.&lt;/P&gt;
&lt;P&gt;Happy testing!&lt;/P&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=5689" width="1" height="1"&gt;</content><author><name>gelexgaray</name><uri>http://geeks.ms/members/gelexgaray/default.aspx</uri></author><category term="Testeo y BI" scheme="http://geeks.ms/blogs/gelexgaray/archive/tags/Testeo+y+BI/default.aspx" /></entry><entry><title>RadarCube for Analysis Services (o cómo el ratón a veces rinde más que el puma)</title><link rel="alternate" type="text/html" href="/blogs/gelexgaray/archive/2006/11/07/RadarCube-for-Analysis-Services-_2800_o-c_F300_mo-el-rat_F300_n-a-veces-rinde-m_E100_s-que-el-puma_2900_.aspx" /><id>/blogs/gelexgaray/archive/2006/11/07/RadarCube-for-Analysis-Services-_2800_o-c_F300_mo-el-rat_F300_n-a-veces-rinde-m_E100_s-que-el-puma_2900_.aspx</id><published>2006-11-07T20:17:00Z</published><updated>2006-11-07T20:17:00Z</updated><content type="html">Ahora que los Office Web Control ya son historia, Microsoft nos ofrece MOSS 2007 y su espectacular Excel Services como soluci&amp;oacute;n de representaci&amp;oacute;n de datos multidimensionales. Hoy lo he estado probando y ver c&amp;oacute;mo se muestran en la web las hojas de trabajo de Excel 2007 por obra y arte de AJAX es espectacular (hablo de la tecnolog&amp;iacute;a, no de cierto producto de limpieza) . Si tenemos Sharepoint implantado en nuestra empresa, no cabe duda de que ser&amp;iacute;a una locura no aprovecharlo...(&lt;a href="http://geeks.ms/blogs/gelexgaray/archive/2006/11/07/RadarCube-for-Analysis-Services-_2800_o-c_F300_mo-el-rat_F300_n-a-veces-rinde-m_E100_s-que-el-puma_2900_.aspx"&gt;read more&lt;/a&gt;)&lt;img src="http://geeks.ms/aggbug.aspx?PostID=6028" width="1" height="1"&gt;</content><author><name>gelexgaray</name><uri>http://geeks.ms/members/gelexgaray/default.aspx</uri></author><category term="Visores OLAP" scheme="http://geeks.ms/blogs/gelexgaray/archive/tags/Visores+OLAP/default.aspx" /></entry><entry><title>UDM, posiblemente lo mejor de Analysis Services 2005</title><link rel="alternate" type="text/html" href="/blogs/gelexgaray/archive/2006/10/24/UDM_2C00_-posiblemente-lo-mejor-de-Analysis-Services-2005.aspx" /><id>/blogs/gelexgaray/archive/2006/10/24/UDM_2C00_-posiblemente-lo-mejor-de-Analysis-Services-2005.aspx</id><published>2006-10-24T17:03:00Z</published><updated>2006-10-24T17:03:00Z</updated><content type="html">&lt;p&gt;El salto cualitativo que ha dado Analysis Services es tal, que cuando uno trata de elegir su caracter&amp;iacute;stica favorita lo puede tener francamente complicado. Hay nuevos algoritmos de miner&amp;iacute;a de datos, tiene la posibilidad de tener cubos con varias tablas de hechos, las &amp;quot;linked measures&amp;quot;, los ETL con flujos de datos y flujos de control separados... sin embargo, si me preguntasen cual es para mi la mejor caracter&amp;iacute;stica de SSAS 2005 no dudar&amp;iacute;a ni un segundo en responder que en el &amp;quot;UDM&amp;quot;.&lt;/p&gt;&lt;p&gt;El UDM, o Unified Dimensional Model, es una capa intermedia que permite a SSAS abstraerse de la fuente de datos en la que se almacenan los hechos y dimensiones de un cubo. De esta forma, ya no necesitamos disponer f&amp;iacute;sicamente de una base de datos con un modelo relacional en estrella, sino que podemos partir de cualquier modelo relacional y construir una &amp;quot;estrella virtual&amp;quot; sobre el UDM. Esta estrella virtual es algo parecido a si organiz&amp;aacute;semos una estrella en base a vistas sobre una base de datos relacional, pero tiene la ventaja de que puede tomar datos desde distintos or&amp;iacute;genes.&lt;/p&gt;&lt;p&gt;&lt;a target="_blank" href="http://geeks.ms/photos/gelexgaray/picture5088.aspx"&gt;&lt;/a&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;img border="0" src="http://geeks.ms/photos/gelexgaray/images/5088/original.aspx" /&gt;&amp;nbsp;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Parece sencillo, &amp;iquest;verdad? &amp;iquest;y por qu&amp;eacute; es a mi entender, la mejor caracter&amp;iacute;stica de SSAS2005? Puede que no parezca una caracter&amp;iacute;stica revolucionaria, pero el UDM nos abre las puertas de la &amp;quot;miner&amp;iacute;a de datos operacional&amp;quot;.&lt;/p&gt;&lt;p&gt;Tradicionalmente, las aplicaciones basadas en tecnolog&amp;iacute;a OLAP se han utilizado para el an&amp;aacute;lisis de datos hist&amp;oacute;ricos: exist&amp;iacute;a un entorno OLTP, un Data Warehouse y un proceso batch, llamado ETL, que transladaba datos de uno a otro. Los cubos OLAP se montaban sobre los datos del Data Warehouse, y por lo tanto estaban disponibles para su an&amp;aacute;lisis &amp;uacute;nicamente tras la ejecuci&amp;oacute;n del ETL (y en el caso de los cubos MOLAP, tras el procesado de los cubos, en los que se cargan los distintos niveles de dimensiones y se construye la base de datos de agregados).&lt;/p&gt;&lt;p&gt;Con UDM, podemos prescindir del Data Warehouse y tomar los hechos directamente del almac&amp;eacute;n OLTP (de ah&amp;iacute; el nombre de &amp;quot;miner&amp;iacute;a de datos operacional&amp;quot;). Incluso podemos tomar datos de varios almacenes OLTP, de una combinaci&amp;oacute;n de almacenes OLTP y DataMarts, o por qu&amp;eacute; no, de datos obtenidos en tiempo real que pudiesen representarse en forma de tabla (cualquier origen OLEDB o ADO.NET puede aportar tablas a nuestro modelo UDM). &lt;/p&gt;&lt;p&gt;&lt;img border="0" src="http://geeks.ms/photos/gelexgaray/images/5090/original.aspx" /&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;Una vez configurados todos los or&amp;iacute;genes de datos (DataSources) podremos unificarlos y darles el aspecto que queramos utilizando un DataSourceView, en el que podremos:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Relacionar tablas&lt;/li&gt;&lt;li&gt;Establecer vistas&lt;/li&gt;&lt;li&gt;Establecer campos calculados&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&amp;iquest;Qu&amp;eacute; ventaja obtenemos con esto? Sencillo... el UDM nos permite romper con la barrera del tiempo y realizar an&amp;aacute;lisis sobre los datos seg&amp;uacute;n se producen. Por supuesto, esto tiene sus implicaciones de rendimiento y su ciencia particular: tendremos que usar ROLAP o HOLAP (configurando adecuadamente la Proactive Cache) para prescindir del procesado de cubos en batch al que nos obliga MOLAP. &amp;iexcl;Uau! &amp;iexcl;Cubos OLAP sin procesos batch! En resumen UDM es una verdadera &amp;quot;revoluci&amp;oacute;n silenciosa&amp;quot; que abre las puertas del OLAP en tiempo real.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=5091" width="1" height="1"&gt;</content><author><name>gelexgaray</name><uri>http://geeks.ms/members/gelexgaray/default.aspx</uri></author><category term="Analysis Services" scheme="http://geeks.ms/blogs/gelexgaray/archive/tags/Analysis+Services/default.aspx" /></entry><entry><title>Business Intelligence y privacidad</title><link rel="alternate" type="text/html" href="/blogs/gelexgaray/archive/2006/10/18/Business-Intelligence-y-privacidad.aspx" /><id>/blogs/gelexgaray/archive/2006/10/18/Business-Intelligence-y-privacidad.aspx</id><published>2006-10-18T18:29:00Z</published><updated>2006-10-18T18:29:00Z</updated><content type="html">&lt;p&gt;El otro d&amp;iacute;a, mientras probaba unos cubos OLAP en la oficina, alguien se me acerc&amp;oacute; y curiose&amp;oacute; a mi espalda. Incre&amp;iacute;ble... estaba cruzando dimensiones y generando informes que hasta ahora las aplicaciones corporativas no pod&amp;iacute;an obtener. Por arte de magia, estaba cruzando aver&amp;iacute;as surgidas en un conjunto de m&amp;aacute;quinas con los operarios que las manejaban en ese momento. Por supuesto se trataba de datos falsos y&amp;nbsp;para mi s&amp;oacute;lo era una prueba explorando las capacidades de los nuevos cubos... pero quien estaba tras de m&amp;iacute; no pudo dejar de recordarme que yo era poco menos que el demonio.&lt;/p&gt;&lt;p&gt;Desde entonces he pensado mucho en el tema. Curiosamente, los grandes vol&amp;uacute;menes de informaci&amp;oacute;n que se tiene de nosotros, garantizan en cierta forma nuestro anonimato. Esta es una afirmaci&amp;oacute;n un tanto chocante y que a m&amp;aacute;s de uno le puede hacer chirriar las tuercas, pero no deja de ser por eso menos verdadera. Todos los d&amp;iacute;as generamos cientos de &amp;quot;pedacitos&amp;quot; de informaci&amp;oacute;n que van quedando en uno y otro lugar, entremezclados con los pedacitos de informaci&amp;oacute;n que han dejado otros. El volumen de datos es tal, que es imposible obtener informaci&amp;oacute;n de ellos, sencillamente porque el bosque es tan inmenso y cerrado,&amp;nbsp;que nos es imposible encontrar un &amp;aacute;rbol concreto. Pero vaya... las tecnolog&amp;iacute;as de Business Intelligence nos facilitan&amp;nbsp; acceder al &amp;aacute;rbol que buscamos... &amp;iexcl;y a todos sus parientes gen&amp;eacute;ticos! &amp;iexcl;y&amp;nbsp;con un par de clicks de rat&amp;oacute;n!&lt;/p&gt;&lt;p&gt;Mi primer pensamiento fue...&lt;/p&gt;&lt;p&gt;Bien, con mi sistema, se puede se puede poner nombre y apellidos a informaci&amp;oacute;n que de otra forma ser&amp;iacute;an puras estad&amp;iacute;sticas an&amp;oacute;nimas. As&amp;iacute; que podemos saber que Serapio es m&amp;aacute;s h&amp;aacute;bil manejando una fresadora que Fulgencio, y que a Fulgencio se le estropea cada dos por tres. &amp;iquest;Perjudica esta informaci&amp;oacute;n a Serapio y Fulgencio? Evidentemente, perjudica a Fulgencio y Beneficia a Serapio. &amp;iquest;Pero es esto malo? &amp;iquest;Soy el demonio? &lt;/p&gt;&lt;p&gt;Mmm... el sistema beneficia a quien lo hace bien, y perjudica a quien lo hace mal. Adem&amp;aacute;s lo hace bas&amp;aacute;ndose en una enorme cantidad de variables, y de forma totalmente imparcial. A mi me parece bastante justo, &amp;iquest;no? Ese d&amp;iacute;a pude dormir tranquilamente, a sabiendas de que mi sistema, en buenas manos, ser&amp;iacute;a una herramienta que permitir&amp;iacute;a impartir justicia.&lt;/p&gt;&lt;p&gt;Pero esa noche tuve una pesadilla... &amp;iquest;En buenas manos?&lt;/p&gt;&lt;p&gt;Al d&amp;iacute;a siguiente, al llenar el dep&amp;oacute;sito de mi coche, pas&amp;eacute; la &amp;quot;Travel&amp;quot; en mi gasolinera habitual... y pens&amp;eacute;, &amp;iexcl;all&amp;aacute; va mi pedacito de informaci&amp;oacute;n!. Pero me qued&amp;eacute; inquieto. &amp;iquest;Ir&amp;aacute; ese pedazo de informaci&amp;oacute;n a buenas manos? &amp;iquest;Qu&amp;eacute; se podr&amp;iacute;a hacer con esa informaci&amp;oacute;n? Amigos m&amp;iacute;os... &amp;iquest;imagin&amp;aacute;is qu&amp;eacute; se puede hacer con las tecnolog&amp;iacute;as actuales de business intelligence sobre la base de datos de &amp;quot;Travel Club&amp;quot;? Y por supuesto, no es s&amp;oacute;lo la Travel... son mis &amp;quot;tracking cookies&amp;quot; cuando navego por Internet, mi &amp;quot;historial&amp;quot; en los distintos sitios web en los que me autentico con un Microsoft Passport (o Windows Live Id) y un mont&amp;oacute;n de actividades que realizo a diario. Muchos, muchos, muchos pedacitos de informaci&amp;oacute;n.&lt;/p&gt;&lt;p&gt;No me considero el demonio... &amp;iexcl;pero estoy seguro de que la misma tecnolog&amp;iacute;a sobre la que escribo en este blog, es un arma de destrucci&amp;oacute;n masiva en manos del Demonio! De hecho, me pregunto qu&amp;eacute; ser&amp;iacute;a de las empresas que desarrollan spyware sin la ayuda del &amp;quot;business intelligence&amp;quot;.&lt;/p&gt;&lt;p&gt;Y llegamos al punto que quer&amp;iacute;a atacar... &amp;iquest;qui&amp;eacute;n, y sobre todo c&amp;oacute;mo, me protege de los abusos? M&amp;aacute;s de uno dir&amp;aacute;, &amp;iexcl;para eso est&amp;aacute; la legislaci&amp;oacute;n, amigo! Entonces comparo mi trabajo con el de quien explota informaci&amp;oacute;n obtenida del spyware, y... &amp;iexcl;vaya!&amp;nbsp;Realmente en algunos casos los hechos pueden ser tremendamente similares, y las tecnolog&amp;iacute;as que empleamos muy parecidas. Realmente nos diferencian las intenciones... &amp;iexcl;pero es que&amp;nbsp;se juzgan los&amp;nbsp;hechos, y no las intenciones!&lt;/p&gt;&lt;p&gt;Bueno, todo esto me ha hecho empatizar con los legisladores... uff, &amp;iexcl;qu&amp;eacute; dif&amp;iacute;cil tiene que ser legislar contra el spyware! Y me surge otra pregunta... &amp;iquest;y si alguien utiliza un sistema creado con buena fe, para obtener informaci&amp;oacute;n que se podr&amp;iacute;a emplear con mala fe... el desarrollador del sistema es responsable en parte?&lt;/p&gt;&lt;p&gt;No me ha quitado demasiado el sue&amp;ntilde;o, porque sigo pensando que la tecnolog&amp;iacute;a es &amp;eacute;ticamente neutra, y que lo moral o inmoral es el uso que se hace de ella. Seguro que los metere&amp;oacute;logos podr&amp;iacute;an sacar chispas al &amp;quot;business intelligence&amp;quot;. Mi conciencia est&amp;aacute; tranquila. Pero los a&amp;ntilde;os me recuerdan que habitualmente, las leyes van tres pasos por detr&amp;aacute;s de la moral.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=4843" width="1" height="1"&gt;</content><author><name>gelexgaray</name><uri>http://geeks.ms/members/gelexgaray/default.aspx</uri></author><category term="Opini&amp;#243;n" scheme="http://geeks.ms/blogs/gelexgaray/archive/tags/Opini_26002300_243_3B00_n/default.aspx" /></entry><entry><title>Paths relativos en Integration Services</title><link rel="alternate" type="text/html" href="/blogs/gelexgaray/archive/2006/10/10/Paths-relativos-en-Integration-Services.aspx" /><id>/blogs/gelexgaray/archive/2006/10/10/Paths-relativos-en-Integration-Services.aspx</id><published>2006-10-10T18:05:00Z</published><updated>2006-10-10T18:05:00Z</updated><content type="html">&lt;p&gt;Uno de los aspectos m&amp;aacute;s molestos de SSIS, es el hecho de que no permita utilizar rutas relativas en las cadenas de conexi&amp;oacute;n a archivos. Esto es un problema si queremos realizar un ETL que se vaya a desplegar en una ruta distinta a la utilizada en tiempo de dise&amp;ntilde;o... pero por fortuna, aunque un poco rebuscado, hay un truco que permite utilizar paths relativos.&lt;/p&gt;&lt;p&gt;Atended pues, a esta receta con la que podr&amp;eacute;is desarrollar un ETL rico, rico, rico... que os permita:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Utilizar archivos como or&amp;iacute;genes de datos sin tener que colocarlos en rutas fijas&lt;/li&gt;&lt;li&gt;Lanzar archivos &amp;quot;dtsx&amp;quot; que se almacenen en el directorio en el que se est&amp;aacute; ejecutando el ETL&lt;/li&gt;&lt;li&gt;... etc, etc, etc...&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Vamos pues, paso a paso con el truquillo:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Lo primero que hay que hacer es definir una variable con el path en el que se desplegar&amp;aacute; el ETL. Definidla de forma que sea global al archivo &amp;quot;dtsx&amp;quot; principal en el que se haya implementado el ETL. Ya sab&amp;eacute;is, se va a la pesta&amp;ntilde;ita de &amp;quot;Control Flow&amp;quot; y se define la varible desde all&amp;iacute;.&lt;/li&gt;&lt;li&gt;Cuando creamos una conexi&amp;oacute;n a un archivo, Integration Services nos obliga a establecer como cadena de conexi&amp;oacute;n, la ruta absoluta a un archivo existente. Pues bien, satisfaremos los deseos de SSIS haciendo que la conexi&amp;oacute;n apunte a un archivo existente.&lt;/li&gt;&lt;li&gt;Seleccionamos &amp;ldquo;Propiedades&amp;rdquo; de la conexi&amp;oacute;n sobre la que queremos establecer la ruta relativa.&lt;/li&gt;&lt;li&gt;Seleccionar &amp;ldquo;Expresiones&amp;rdquo; (pinchamos en los tres puntitos al lado de &amp;quot;expressions&amp;quot; en la ventana de propiedades).&lt;br /&gt;&lt;br /&gt;&lt;a target="_blank" href="http://geeks.ms/photos/gelexgaray/picture4264.aspx"&gt;&lt;img border="0" width="325" src="http://geeks.ms/photos/gelexgaray/images/4264/original.aspx" height="448" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Seleccionar &amp;ldquo;ConnectionString&amp;rdquo;&lt;br /&gt;&lt;br /&gt;&lt;a target="_blank" href="http://geeks.ms/photos/gelexgaray/picture4265.aspx"&gt;&lt;img border="0" width="438" src="http://geeks.ms/photos/gelexgaray/images/4265/original.aspx" height="341" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Establecer una expresi&amp;oacute;n que construya un path absoluto en funci&amp;oacute;n de la variable con el path de despliegue: en&amp;nbsp;mi ejemplo, @[User::DeploymentPath] + &amp;quot;&lt;a&gt;\\Data\\DayOfWeekNameValues.txt&lt;/a&gt;&amp;quot;. Esta expresi&amp;oacute;n, se resolver&amp;aacute; en tiempo de ejecuci&amp;oacute;n y sobreescribir&amp;aacute; el valor de la propiedad que hubi&amp;eacute;semos establecido en tiempo de dise&amp;ntilde;o.&lt;br /&gt;&lt;br /&gt;&lt;a target="_blank" href="http://geeks.ms/photos/gelexgaray/picture4266.aspx"&gt;&lt;img border="0" width="575" src="http://geeks.ms/photos/gelexgaray/images/4266/original.aspx" height="509" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Por &amp;uacute;ltimo, deberemos propagar el valor de la variable a paquetes hijos, por medio de la opci&amp;oacute;n &amp;quot;SSIS-&amp;gt; Package Configurations&amp;quot;. De todas la opciones disponibles, seleccionaremos la opci&amp;oacute;n de tomar una configuraci&amp;oacute;n de una variable desde el paquete padre.&lt;br /&gt;&lt;br /&gt;&lt;a target="_blank" href="http://geeks.ms/photos/gelexgaray/picture4267.aspx"&gt;&lt;img border="0" width="681" src="http://geeks.ms/photos/gelexgaray/images/4267/original.aspx" height="604" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a target="_blank" href="http://geeks.ms/photos/gelexgaray/picture4268.aspx"&gt;&lt;img border="0" width="493" src="http://geeks.ms/photos/gelexgaray/images/4268/original.aspx" height="442" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;La variable que marca la ruta al paquete, tambi&amp;eacute;n puede configurarse desde &amp;quot;SSIS-&amp;gt; Package Configurations&amp;quot;. La opci&amp;oacute;n m&amp;aacute;s adecuada en este caso, es tomar su valor de una entrada de registro, o de una variable de entorno (consultad los libros en pantalla, que las entradas de registro tienen que tener un formato espec&amp;iacute;fico).&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Bueno, espero que os haya gustado mi primer post tras la vuelta de vacaciones. Os deseo un buen comienzo de curso, y ya sab&amp;eacute;is... &amp;iexcl;felices transformaciones!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=4214" width="1" height="1"&gt;</content><author><name>gelexgaray</name><uri>http://geeks.ms/members/gelexgaray/default.aspx</uri></author><category term="Integration Services" scheme="http://geeks.ms/blogs/gelexgaray/archive/tags/Integration+Services/default.aspx" /></entry></feed>