lunes, 9 de julio de 2012

Introducción a 960 Grid System

En este post empezaré diciendo que no soy diseñador sino programador. Es por eso que siempre estoy buscando soluciones para maquetar más rápido en HTML/CSS y sobre todo, maquetar más sencillo. En esta búsqueda, he descubierto recientemente el mundo de los framework CSS y más concretamente, el concepto Grid CSS.

En el blog de Koalite, hay un interesantísimo artículo que habla sobre ello Diseño Web Sensible y Grids CSS.

También hay disponible un excelente tutorial en desarrolloweb.com, http://www.desarrolloweb.com/manuales/maquetacion-css-960-grid-system.html y otro tutorial más en http://jepserbernardino.com/idea/960-grid-un-framework-para-css/

Yo por mi parte voy a apostar inicialmente por 960 Grid System para un par de sencillos proyectos que tengo que abordar próximamente.

En mis propias palabras, 960gs es un framework CSS que nos permitirá maquetar nuestras páginas web como si estuviéramos trabajando con tablas HTML. Está claro que por hoy por hoy maquetar con tablas es contra-natura, pero también hay que reconocer que maquetar con tablas (y siempre que no las anidaras excesivamente) era sencillo e intuitivo y sobre todo, muy accesible para los maquetadores noveles. Siendo así, 960gs combina para mí un diseño tableless con bondades similares a la maquetación con tablas (y que nadie me crucifique por hablar de bondades en lo relativo a tablas, ¿eh?)

Como el movimiento se demuestra andando, veamos un sencillo ejemplo con 960grid.

Queremos maqueta una típica página maestra de backend. Algo parecido a esto:

clip_image002

Está claro que este diseño tampoco supone un reto de gran calibre, pero
¿Por qué pegarse con float, width, height, etc. si puedo hacerlo más sencillo con 960gs?

Veamos el código necesario para llevarlo a cabo:

<div class="container_12">
    <div id="header" class="grid_3 prefix_9">
        header
    </div>
    <div class="clear">
    </div>
    <div id="logo" class="grid_12">
        logo</div>
    <div class="clear">
    </div>
    <div id="menu" class="grid_12">
        menu</div>
    <div class="clear">
    </div>
    <div id="sidebar" class="grid_3">
        sidebar</div>
    <div class="grid_9">
        <div id="title" class="grid_7 alpha">
            title</div>
        <div id="help" class="grid_2 omega">
            help</div>
        <div class="clear">
        </div>
        <div id="content" class="grid_9 alpha">
            content</div>
    </div>
    <div class="clear">
    </div>
    <div id="footer" class="grid_12">
        footer</div>
</div>

El resultado es el siguiente (he activado ver los bordes de los DIV desde la IE Developer Toolbar):


image


image


Como podemos comprobar hemos podido crear el layout de nuestra página con poco código y poco esfuerzo.


Ciertamente tampoco quiero dar demasiado misterio al concepto de framework CSS.
En resumen, nos son más (ni menos tampoco) que 3 ficheros css que tenemos que incluir en la cabecera de nuestra página.

<link href="StyleSheets/reset.css" rel="stylesheet" type="text/css" />
<link href="StyleSheets/text.css" rel="stylesheet" type="text/css" />
<link href="StyleSheets/960.css" rel="stylesheet" type="text/css" />


  • reset.css es un reseteador de estilos para intentar homogenizar la visualización en todos los navegadores.

  • text.css es una hoja de estilos que define los estilos básicos de texto (h1…h6, p, etc.)

  • 960.css es realmente quien define la rejilla.

Las clases definidas en el fichero 960.css son:


container_12 y container_16 que tiene que ser asignadas al DIV contenedor de una rejilla. Digo “una” rejilla porque se pueden anidar columnas e incluso podemos tener varias rejillas al mismo nivel en la misma página (incluso de distinto número de columnas).


Si no tenemos suficiente con una división de 12 o 16 columnas, también podemos utilizar el generador on-line para definir el número, anchura y margen entre columnas desde http://grids.heroku.com/


Después de haber definido el contenedor, tenemos las clases grid_1 hasta grid_12 o grid_16, que lo que hacen es definir el número de columnas que utilizará cada uno de nuestros DIV.


También tenemos las clases alpha y omega, que sirven al propósito de eliminar el margen izquierdo y derecho, respectivamente, cuando anidemos columnas dentro de otras columnas. En líneas generales, primera columna de una columna anidada tiene que llevar alpha y última columna de una columna anidada tiene que llevar la clase omega. Todo ello para eliminar margen izquierdo de la primera columna y margen derecho de la última columna.


Si queremos crear espacios en blanco antes o después del contenido, tenemos igualmente las clase prefix_1 hasta prefix_11 o prefix_15 y la clase suffix_1 hasta suffix_11 o suffix_15.


Para limpiar los floats, tenemos la clase clear que tendremos que meter siempre después de una separación horizontal.


Como últimas clases disponibles, también es posible alterar o intercambiar columnas en lo relativo a su posición con las clases pull y push. Más información sobre reorganizar las columnas en http://www.clubosc.com/960-grid-tutorial-understanding-push-and-pull-classes.html


Por último, también hay herramientas disponibles para ver la grilla en Photoshop o desde el mismo navegador (esto nos ayudará bastante a la hora de plantear el Layout a conseguir con 960gs). Por ejemplo y ver la grilla en el navegador podemos seguir las instrucciones de esta página http://peol.github.com/960gridder/ que lo que hace es agregar un bookmarklet al navegador para cargar un overlay con la grilla.


image


Está claro que para mi las grillas CSS son aún un terreno por explorar y sobre todo llegar al convencimiento de que son útiles y no intentar utilizar para nada más que para lo que son, es decir, Layouts.


Un saludo.

miércoles, 4 de julio de 2012

Acciones disponibles en máquinas virtuales de Hyper-V

En la oficina hemos estrenado recientemente un nuevo servidor Windows 2008 R2 y hemos apostado por la virtualización para intentar ahorrar costes.

En este post no voy a hablar sobre la virtualización (sobre todo porque no soy ninguna voz autorizada), pero a cambio explicaré cuales son las acciones que pueden llevarse a cabo sobre una máquina virtual.

Aunque en principio podría no parecer necesario hablar sobre estas acciones, lo cierto es que cada vez que accedo al Administrador de Hyper-V, tengo que recordar cual era la diferencia entre Apagar y Desconectar, qué era Guardar, etc.

Sin más dilación, hay van las acciones disponibles para una máquina virtual:

Conectar.

Esta acción simplemente abre una nueva ventana para acceder a la máquina virtual.

Aunque parezca de Perogrullo, cerrar esta ventana no conlleva ninguna acción para la máquina virtual.

Desconectar

Aunque en principio podría parecer que es la acción opuesta a Conectar, nada más lejos de la realidad. Desconectar es y, haciendo el símil con una máquina física, como si apagáramos la corriente. Es decir, es una apagado forzado de la máquina virtual.

image

Iniciar

Iniciar es encender la máquina virtual, es arrancar el sistema operativo invitado.

Apagar

Al igual que Desconectar forzaba un apagado forzado, Apagar fuerza un apagado controlado.
Es el equivalente a apagar la máquina virtual desde el botón Inicio > Apagar del propio Windows de la máquina virtual.

Guardar

Guardar permite guardar el estado actual de la máquina virtual y ponerla fuera de línea.

Es similar a hibernar en un PC de escritorio o portátil.

Después de Guardar,  podremos volver a activar la máquina virtual con la acción Iniciar (que es junto a Instantánea las únicas opciones disponibles después de Guardar)

Pausar

Esta acción deja fuera de línea a la máquina virtual pero no guarda su estado.

Después de Pausar, sólo podremos Desconectar, Guardar o Reanudar.

La opción que normalmente acompaña a Pausar es Reanudar que vuelve a dejar operativa la máquina virtual.

Reanudar

Como hemos dicho antes, Reanudar sirve al propósito de volver a dejar operativa una máquina virtual después de Pausar.

Reestablecer

Esta opción permite reestablecer la máquina virtual al estado que tenía al arrancarla.

Esto permite deshacer los cambios realizados en la máquina virtual desde el actual arranque de la misma.

image

Instantanea

Toma una instantánea de la máquina virtual.

Revertir

Sólo en caso de que la máquina virtual disponga de instantáneas, Revertir aplicará automáticamente la última instantánea.

image

Algunos otros enlaces que podrían ser de utilidad son los siguientes:

Hyper-V: 5 Ways to Transfer Files Between Physical and Virtual Host http://ketstech.blogspot.com.es/2015/04/hyper-v-5-ways-to-transfer-files.html

Removing the ghost Hyper-V vNic adapter when using Converged Networks after in-place upgrade to W2012R2 http://cloudtidings.com/2013/11/20/removing-the-ghost-hyper-v-vnic-adapter-when-using-converged-networks-after-in-place-upgrade-to-w2012r2/

Using Hyper-V with a Wireless Network Adapter http://blogs.msdn.com/b/virtual_pc_guy/archive/2008/01/09/using-hyper-v-with-a-wireless-network-adapter.aspx

Un saludo!

martes, 19 de junio de 2012

Reciclaje de grupos de aplicaciones en IIS

Lo cierto es que, aunque conocía la característica de reciclaje de un grupo de aplicaciones de IIS, hasta hoy no había tenido la necesidad de meterme con ella en serio.

Normalmente, cuando subo una aplicación a IIS los únicos parámetros que configuro del grupo de aplicaciones es seleccionar la versión del .NET Framework correcta. En la mayoría de los casos no hay mucho más que hacer al respecto pero, como te mostraré a continuación, en según qué escenarios podría no ser suficiente.

Imagina una aplicación que realiza ciertas tareas pesadas o críticas (lo dejo a tu elección) al arranque de la aplicación (por ejemplo en el evento Application_OnStart del fichero global.asax).

Con este escenario ¿Sabes con certeza en que momentos será ejecutado tu código de inicialización? Está claro que se ejecutará al levantar el grupo de aplicaciones asociado a tu aplicación pero ¿Cuándo y porqué se vuelve a levantar tu grupo de aplicaciones?

Las respuestas más obvias es que un grupo de aplicaciones se iniciará en los siguientes casos:

  • Reinicio del servicio W3C
    • Bien sea de forma manual, bien porque se ha reiniciado el servidor, etc.
  • Reinicio o reciclaje manual del grupo de aplicaciones.
    • Acto totalmente voluntario y, por ende, controlable.
  • Cambios en la configuración de la aplicación (web.config, global.asax, etc.).
    • De nuevo un acto voluntario y programable.

A partir de aquí es cuando me he encontrado que, muy diversos factores también podrían forzar el reciclaje del grupo de aplicaciones y, por consiguiente, que mi código pesado de inicialización volviera a ejecutarse cuando yo no lo tenía previsto.

Si accedemos a la “configuración avanzada” de un grupo de aplicaciones desde la consola de administración de IIS, las secciones que podrían interesarnos son: Modelo de proceso y Reciclaje.

clip_image001[4]

Sin meternos en configurar límites de memoria o CPU, que al ser alcanzados provocarían el reciclaje de la aplicación, hay otros valores que “de serie” pueden hacer que nuestro grupo de aplicaciones se recicle sin nosotros haberlo previsto. Principalmente estoy hablando de “Tiempo de inactividad” e “Intervalo de tiempo regular”.

“Tiempo de inactividad” ha sido el mayor de mis problemas durante algún tiempo y, de hecho, es el valor que ha originado la redacción de este post. Este valor indica un cantidad de minutos en las que, sino hay actividad en el servidor, el grupo de aplicaciones será reiniciado.

En IIS 7.5 tiene por defecto el valor 5, lo que significa que si en 5 minutos nadie hace una petición a tu aplicación… el grupo de aplicaciones se reciclará.

Por otro lado, “Intervalo de tiempo regular” es un valor, también expresado en minutos, después de los cuales se reciclará el grupo de aplicaciones, con independencia de si están o activas las aplicaciones del grupo.

Por defecto son 1740 minutos (29 horas).

En esta situación resulta que tengo una aplicación que se recicla después de 5 minutos de inactividad y además cada 29 horas… luego se recicla cuando quiere y no tengo nada controlado el tema!

Para solucionar esto he optado por utilizar el valor “Horas específicas”, que permite especificar una o más horas en las cuales será reciclado el grupo de aplicaciones. En mi caso he pasado de un “reciclado aleatorio” a un “reciclado determinista”. Además, al especificar “Horas específicas” ya no se tiene en cuenta el valor de “Intervalo de tiempo regular”.

Por otro lado (y como no quiero ser un killer server), tampoco voy a poner 0 en “Tiempo de inactividad”… pero tampoco voy a dejar 5 (es más que probable que un usuario esté en mi página sin generar tráfico durante 5 minutos)… así que pondré un valor más alto (por ejemplo 20 para coincidir con el Session.Timeout).

Llegados a este punto creo tener algo más controlado cuando se reciclará mi grupo de aplicaciones, pero ¿Cómo puedo confirmar que mi nueva política de reciclaje se está llevando a cabo? Pues registrando los reciclados en el visor de eventos de Windows.

clip_image002[4]

Ahora cada vez que se recicle el grupo de aplicaciones podré consultar el visor de eventos y ver algo parecido a esto:

clip_image004[4]

clip_image006[4]

Está claro que la administración de un servidor IIS probablemente no sea tarea de un programador pero, al final, siempre acaba siendo tu tarea controlar el entorno donde se ejecuta tu aplicación y supervisar el rendimiento de la misma.

Aunque no es el propósito de este post, parece ser (no lo he comprobado) que la sección “Modelo de proceso” se puede especificar a través del fichero de configuración de nuestra aplicación (web.config) http://technet.microsoft.com/es-es/library/cc779563(v=ws.10).aspx. Sin embargo, la sección “Reciclaje” parece que no http://stackoverflow.com/questions/9697119/disable-iis7-pool-recycling-from-asp-net-config 

Por último, si quieres una referencia exacta de estas 2 secciones, puedes visitar los siguientes enlaces:

Process Model Settings for an Application Pool <processModel>

http://www.iis.net/ConfigReference/system.applicationHost/applicationPools/add/processModel

Recycling Settings for an Application Pool <recycling>

http://www.iis.net/ConfigReference/system.applicationHost/applicationPools/add/recycling

Un saludo!

miércoles, 30 de mayo de 2012

Diferencias entre bind, live, delegate y on

Está claro que una de las partes fundamentales de jQuery es el manejo de eventos, pero cuando tenemos que ponernos manos a la obra se nos presentan distintas opciones y no siempre sabemos cual es la idónea.

A nuestra disposición tenemos diversas funciones que aparentemente hacen lo mismo:

·         bind

·         live

·         delegate

·         on

El porqué de esta diversidad es fruto de querer hacer una mejor librería jQuery a la vez que se mantiene retrocompatibilidad con versiones anteriores del producto. Aquí está claro que no todos los proyectos pueden cambiar de jQuery 1.0 a jQuery 1.7.2 sin que ello conlleve una refactorización de código de magno esfuerzo.

Cronológicamente hablando (y espero no equivocarme), la primera función en aparecer en escena fue bind. Después apareció live para cubrir un hueco que no llenaba bind (la delegación de eventos), pero enseguida vieron que live no funcionaba como se esperaba de ella, así que incorporaron delegate en detrimento de live. Por último y para evitar que la gente se volviera loca teniendo que decidir si utilizar bind, live o delegate, surgió on, que en un solo método reúne la funcionalidad de todos los métodos anteriores.

Una vez que ya tenemos claro el orden cronológico de aparición de todos estos métodos, la siguiente pregunta a contestar sería ¿Por qué apareció live? ¿Qué es eso de la delegación que bind no podía hacer?

Con bind podemos adjuntar manejadores de eventos (o callbacks en terminología javascript) a elementos existentes en el DOM. Lo cierto es que bind siempre ha funcionado maravillosamente bien pero tiene un grave problema cuando nos encontramos en escenarios donde el DOM cambia dinámicamente (por ejemplo aplicaciones con AJAX). El problema está en que bind adjunta manejadores sólo a elementos existentes, es decir, futuros elementos que se incorporen al DOM no sabrán nada de los eventos manejados por bind (aunque coincidan con el selector suministrado a bind).

Por ejemplo pensemos que tenemos un ul con un solo li hijo. Adjuntamos un manejador al evento click en los li hijos del elemento ul (no sólo para el único hijo existente, sino en general para todos los hijos li de ul). Cada vez que hagamos click en un li agregaremos un nuevo li al ul padre. ¿Si hacemos click en los nuevos elementos li creados dinámicamente se disparará nuestro manejador? Pues no, porque bind adjuntó el evento sólo a elementos existentes en el momento de su declaración, así que nuevos elementos que coinciden con nuestro selector de bind no se darán por aludidos.

    <ul id="lista">

        <li>1</li>

    </ul>


$(document).ready(function () {

    $("#lista li").bind("click", function () {

        var ul = $(this).parent();

        var length = ul.children().length;

        // aunque el nuevo li coincide con el selector $("#lista li"), bind no funcionará con el nuevo elemento recién agregado

        ul.append("<li>" + (length + 1) + "</li>");

    });

});


Lógicamente tenemos un problema con este código ¿Cómo adjuntar o re-adjuntar nuestro manejador a los nuevos elementos li? Pues para eso apareció live.

Live funciona con la delegación de eventos, es decir, es vez de adjuntar el manejador click al único elemento li presente que cumplía el selector $("#lista li") en el momento de la declaración, lo que hace es declarar un manejador global a elementos que coincidan con el selector, esto es tanto a elementos que existen ahora como elementos que vayan a existir en el futuro.

Veamos ahora que nuestro código sólo requiere un simple cambio para trabajar con live en vez de con bind.

$("#lista li").live("click", …

 

A partir de este momento, cualquier elemento li que sea hijo de #lista tendrá adjunto el manejador de evento especificado (danto igual si el hijo existía en el momento de la declaración del manejador o fue creado después de forma dinámica).

El principal problema del que adolece live es que para hacer funcionar la delegación de eventos, adjunta el manejador al elemento document. De este forma, cada vez que se haga click en el documento (en cualquier sitio del documento) se chequeará si el elemento clicado coincide con el selector $("#lista li"), y si coincide se lanzará el evento.

Para solucionar el cómo funciona live, rápidamente se incorporó delegate.

Delegate respeta el mismo principio de delegación de eventos que live, pero a diferencia de éste, delegate adjunta el manejador a un padre específico. De esta forma ya no podemos hablar de un manejador global, sino de un manejador local con un ámbito concreto.

Para adaptar nuestro código a delegate, tenemos ahora que especificar un padre y un selector de hijos que se validarán ahora y en el futuro:

$("#lista").delegate("li", "click", function () { …

 

Si nos fijamos, con delegate hemos especificado que queremos adjuntar el manejador click a todos los hijos li (ahora y el futuro) para el padre #lista. Y todo esto confinado a un padre, es decir, sólo se chequeará el selector si el click sucede dentro de #lista, no a nivel de documento como sucedía con live.

Llegados a este punto está claro que hemos descartado live y sólo nos quedaría elegir entre bind y delegate según el escenario, pero lo cierto es que utilizando la nueva función on podemos olvidarnos de todo lo anterior y tener en un solo método toda la funcionalidad de bind y delegate.

Por ejemplo nuestro código anterior con bind pasaría a ser:

$("#lista li").on("click", function () { …


Y nuestro anterior delegate sería ahora:

$("#lista").on("click", "li", function () { …

 

Como vemos, con on podemos tanto gestionar eventos al estilo de bind (sólo para elementos existentes) como al estilo de delegate (con delegación de eventos para elementos futuros).

Ya no tienes excusa… utiliza on ... que no lo digo yo, lo dice jQuery!

Un saludo!

viernes, 11 de mayo de 2012

ResolveUrl en un servicio web de ASP.NET

Si programas en Web Forms estarás muy acostumbrado a utilizar los métodos ResolveUrl y ResolveClientUrl para devolver direcciones Url al código de cliente a partir de direcciones de ASP.NET (es decir, aquellas direcciones que son relativas a la raíz del proyecto y que comienzan con el carácter ~)

Los métodos ResolveUrl y ResolveClientUrl son métodos de la clase System.Web.UI.Control y es por ello que están disponibles tanto en un WebForm (.aspx) como en un control de usuario (.ascx).

Sin embargo, si estamos ejecutando código en un servicio web de ASP.NET (.asmx) no tenemos disponible estas funciones (porque un servicio web hereda de System.Web.Services.WebService) y lógicamente puede ser que queremos devolver al cliente direcciones url válidas a partir de direcciones del tipo ASP.NET (recuerda que son aquellas que incluyen el carácter ~).

En esta situación, nos será muy útil una función como la siguiente que “simula” el comportamiento de ResolveUrl y ResolveClientUrl. Digo “simula” porque con esta función estamos devolviendo rutas absolutas en vez de relativas, pero en cualquier caso estamos devolviendo rutas que el cliente puede consumir.

Imports System.Web
Public Class Utilities
    Public Shared Function ResolveUrl(ByVal url As String) As String
        Dim webApplicationRootUrl = _
            String.Format("{0}://{1}{2}", _
                HttpContext.Current.Request.Url.Scheme, _
                HttpContext.Current.Request.ServerVariables.Item("HTTP_HOST"), _
                HttpContext.Current.Request.ApplicationPath)
        If Not webApplicationRootUrl.EndsWith("/") Then
            webApplicationRootUrl &= "/"
        End If
        url = url.Substring(2) ' Quitar ~/
        url = webApplicationRootUrl & url
        Return url
    End Function
End Class

Ahora por ejemplo para una llamada a ResolveUrl("~/Default.aspx"), el método nos devolverá una dirección absoluta como http://localhost:7572/WebSite1/Default.aspx donde:


  • http es el esquema.
  • localhost:7572 es la variable HTTP_HOST
  • WebSite1 es la ruta a la aplicación.
  • Default.aspx es la url suministrada al método.

Un saludo!

martes, 10 de abril de 2012

Table Splitting y Entity Splitting en Entity Framework

Hay 2 conceptos de modelado en Entity Framework que podrían resultarnos útil en determinados escenarios. Estoy hablando de Table Splitting y Entity Splitting.

Table Splitting

Table Splitting hace mención al hecho de mapear una tabla a dos o más entidades de nuestro modelo, entre las cuales habrá una relación 1:1.

Los motivos que pueden empujarnos a llevar a cabo esta práctica podrían ser:

  • Dividir una entidad de nuestro modelo que tiene muchas propiedades, en varias entidades con menos campos y más manejables. Es decir, organizar mejor nuestro modelo.
  • Hacer lazy loading a determinados campos. Imagina que un campo es del tipo ntext y tiene “chorrocientos” caracteres que sólo consultaras en ocasiones muy puntuales. Sería una pena forzar, tanto la consulta SQL contra la base de datos como la carga del mismo dato en una entidad en memoria, cada vez que leyeras una entidad.

Un ejemplo sería una tabla como la siguiente:

clip_image001

Que finalmente se mapeará en nuestro modelo con las siguientes entidades:

clip_image002

Si te fijas, lo que hemos hecho ha sido:

  • Crear una entidad Producto mapeada contra la tabla Productos, con sólo la propiedad Descripcion (además de la propiedad IdProducto que es la clave de la tabla).
  • Crear una entidad Propiedad mapeada también contra la tabla Productos, con las propiedades del 1 al 6 (justo las que no están mapeadas en la entidad Producto y además también la propiedad IdProducto).
  • Crear una  asociación 1:1 entre ambas entidades.

A partir de aquí, para el tratamiento de esta entidad sólo debemos tener en cuenta algunos puntos de interés:

Insertar una entidad

Al insertar una entidad deberemos insertar en un solo paso (una llamada a SaveChanges) todas las entidades que hayamos creado como producto del Table Splitting. Es decir, algo como lo siguiente no funcionaría porque sólo estamos haciendo el insert de una entidad y no de sus entidades relacionadas  (incluso cuando todas las propiedades de las entidades relacionadas 1:1 en nuestro Table Splitting, admitan valores nulos):

Dim p As New Producto With {.IdProducto = 1, .Descripcion = "Xbox 360"}

ctx.Productos.AddObject(p)

 

ctx.SaveChanges()

 

clip_image003

Lo correcto sería:

Dim p As New Producto With {.IdProducto = 1, .Descripcion = "Xbox 360"}

ctx.Productos.AddObject(p)

 

Dim prop As New Propiedad

p.Propiedades = prop

 

ctx.SaveChanges()

 

Resumiendo, un INSERT tiene que  disponer de todos los campos de la tabla para llevar a cabo la operación.

Eliminar una entidad

Al igual que ocurre al insertar la entidad, deberá eliminarse toda la entidad como un bloque.

Entity Splitting

Esta técnica es justamente contraria a Table Splitting.

Con Entity Splitting lo que hacemos es mapear dos o más tablas de nuestra base de datos en una sola entidad en nuestro modelo.

El principal motivo para hacer Entity Splitting es, normalmente, aunar en una entidad del modelo varias tablas que conceptualmente son el mismo registro.

Por ejemplo, partiendo de las siguientes tablas de base de datos:

clip_image004

Llegaremos al siguiente modelo de EF:

clip_image005

clip_image006

Ahora un código como el siguiente grabará en ambas tablas de nuestra base de datos:

Dim p As New Productos

p.IdProducto = 1

p.Descripcion = "Xbox"

p.Propiedad1 = "360"

ctx.Productos.AddObject(p)

 

ctx.SaveChanges()

 

Espero haber dejado claro estos conceptos y que te sirvan de ayuda.

Un saludo.

Microsoft Reporting Viewer y despliegue privado

Llevamos algún tiempo utilizando Microsoft Reporting Viewer y en entornos de hosting compartido donde no se tiene acceso al servidor, resulta imposible distribuir y ejecutar el run-time que recomienda Microsoft. Microsoft Report Viewer 2010 Redistributable Package

De este modo y a prueba “ensayo-error”, veremos cuales son los pasos necesarios para realizar una distribución privada de los ensamblados que necesita Microsoft Reporting Viewer para funcionar. Es decir, vamos a llevar a cabo un private deployment.

Nuestro entono de pruebas es un servidor Windows 2008 R2 y el despliegue privado ha sido probado tanto para un sitio web como para un proyecto de aplicación web.

Si subimos una aplicación sencilla con un solo formulario y un control ReportViewer y un fichero .rdlc (el informe en sí mismo), el primer error será el siguiente:

clip_image002

Este error nos informa de que no encuentra el ensamblado Microsoft.ReportViewer.Webforms. En realidad, cuando agregamos el control ReportViewer también se agregaron automáticamente las siguientes referencias a ensamblados de nuestro GAC:

·         Microsoft.ReportViewer.Common

·         Microsoft.ReportViewer.WebForms

Para solucionar este error, basta con copiar desde el GAC (C:\Windows\assembly\GAC_MSIL) los anteriores ficheros en el directorio \bin de nuestra aplicación.

Si volvemos a ejecutar de nuevo nuestra página con nuestro visor, ahora el error será el siguiente:

clip_image003

Vaya! Parece que también tendremos que copiar el ensamblado Microsoft.ReportViewer.ProcessingObjectModel a nuestro directorio \bin.

Hecho esto nuestro informe funcionará correctamente con un despliegue privado del run-time de Microsoft Reporting Viewer.

Un saludo.