lunes, 15 de septiembre de 2014

Cuando necesitas pasar un objeto lista a un procedimiento almacenado...


Hello world,
En estos últimos días me he encontrado con la necesidad de pasar una lista de guids a un procedimiento almacenado. Para esto me planteé varias opciones:
  1. Pasar un string con toda la lista de guids concatenados y separados por comas (solución fea, fea aunque "efectiva").
  2. Crear una tabla temporal, donde previamente insertaría todos los guids, ejecutar la consulta sobre ella y posteriormente borrarla (solución más limpia pero mucho más costosa y de muchísimo peor rendimiento).
  3. Investigar un poco y ver cómo solucionar el problema...
Al final opte por el punto 3, y con seguí la siguiente solución.  Lo primero es crearte un tipo en base de datos, para esto ejecutaremos la siguiente sentencia:
CREATE TYPE [dbo].[GuidList] AS TABLE(
[Id] [uniqueidentifier] NULL
)
Con esto con seguiremos el siguiente objeto en nuestra base de datos:

 
Por otro lado, en nuestro procedimiento almacenado para utilizarlo es muy simple, En el siguiente ejemplo muestro como hacer una consulta con un “in” sobre mi tipo GuidList:
CREATE PROCEDURE [dbo].[GetCountries_ByIds] (@CountriesId GuidList READONLY)
AS
BEGIN
SELECT
       CountryId,
       CountryDescription
FROM
       Country
       CountryId IN (SELECT Id FROM @CountriesId)
END

En cuanto a la gestión de este tipo de parámetro en nuestro código, es tan sencillo como crearnos un dataTable con  la información que necesitamos pasar, y asignárselo a un parámetro:
var dtCountries = new DataTable();
dtCountries.Columns.Add("Id");
if (CountryId != null)
       CountryId.ForEach(x =>
       {
            var r = dtCountries.NewRow();
            r[0] = x;
            dtCountries.Rows.Add(r);
        });
var CountriesIdSQLParameter = new SqlParameter("@CountriesId", dtCountries);
using (var reader = this.iAdoSqlHelper.ExecuteReader(iConfiguration.ConnectionString,   SqlCommandText.SP_GetCountries_ByIds, CommandType.StoredProcedure, CountriesIdSQLParameter))
...
...
...
Con estos simples pasos, tendremos una manera más limpia y eficiente de poder pasar un objeto de tipo lista a un procedimiento almacenado.

Hasta el próximo post! 

viernes, 12 de septiembre de 2014

MVC: ActionLink a otro controlador

Hello world,

Desarrollando una de mis primeras paginas con MVC, me he encontrado con el problema de tener que hacer una llamada a un controlador distinto al que tiene mi vista. Como seguramente todos sabéis, para hacer la llamada a la misma vista es tan simple como muestro en el siguiente ejemplo:

@Html.ActionLink("TextoDelLink", "NombreDelAction", "NombreDelControlador", new { id = item.id })

Con esto ya tendríamos creado nuestro link a una nueva vista, siempre y cuando esta esté dentro del mismo controlador. Ahora bien, si lo que necesitamos es llamar a una de vista de otro controlador, seria suficiente con añadir un parámetro mas, el valor de este parámetro seria null, quedando de la siguiente manera:

@Html.ActionLink("TextoDelLink", "NombreDelAction", "NombreDelControlador", new { id = item.id }, null)

Para los no puestos en materia, explicaré cada uno de los parámetros:
  • TextoDelLink: Este es el texto que se muestra en el link.
  • NombreDelAction: Nombre del Action que hemos creado en nuestro controlador.
  • NombreDelControlador: Nombre del la clase del controlador.
  • new { id = item.id }: Lista de parámetros que queremos pasar a la nueva vista.
Con estas líneas tendremos montados nuestros links a otras vistas, tanto del mismo controlador, como de distinto controlador.


 
 
 

Arquitectura DDD y sus capas

Hello world,
Desde hace poco tiempo estoy trabajando con “arquitectura DDD”, y con este post pretendo hacer una breve introducción a este tipo de arquitectura y explicar la funcionalidad de cada una de sus capas. No entraré en demasiados detalles técnicos, para eso ya existen libros donde profundizar mucho más en este tipo de arquitectura.
 
¿Qué es DDD (Domain Driven Design)?
Es un tipo de arquitectura de software orientada a dominio (ámbito para el cual estamos desarrollando la aplicación), donde éste es el que se encargará de guiar el desarrollo del software. El objetivo principal es conseguir tener un modelo de dominio rico y que vaya creciendo poco a poco con las nuevas implementaciones.
 
¿Qué es el Dominio?
El dominio es donde se definen los procesos y las reglas de negocio de nuestra aplicación, es decir, es donde se define la funcionalidad de la aplicación.
 
Capas de arquitectura DDD.
Antes de nada pongamos un simple diagrama de capas en las que se divide:
 


Un ejemplo de distribución de las capas en el Visual Studio seria el siguiente:

Ahora pasaremos a explicar cada una de las capas empezando por la parte superior:
 
1.      UserInterface: Esta será nuestra capa de presentación. Aquí pondremos nuestro proyecto MVC, ASP, o lo que utilicemos como front-end de nuestra aplicación.
 
2.      Application: Esta capa es la que nos sirve como nexo de unión de nuestro sistema. Desde ella se controla y manipula el domain. Por ejemplo, dada una persona se requiere almacenar información de un hijo que acaba de nacer. Esta capa se encargará de: llamar a los repositorios del domain para obtener la información de esa persona, instanciar los servicios del domain y demás componentes necesarios, y por ultimo persistir los cambios en nuestra base de datos.
En esta capa también crearíamos interfaces e implementaciones para servicios, DTOs etc, en caso de que fuese necesario.
 
3.      Domain: En domain podemos ver que hay 3 proyectos:
3.1.   Entities: En el cual tendremos nuestras entidades. Es decir, es una clase donde se definen los atributos de la entidad.
Una entidad tiene una clave que es única y la diferencia de cualquier otra entidad. Por ejemplo, para una clase Persona, podríamos tener los siguientes atributos: Nombre, Apellidos y fecha de nacimiento, en ellos tendríamos la información para la clase Persona.
Una entidad no sólo se ha de ver como una simple clase de datos, sino que se ha de interpretar como una unidad de comportamiento, en la cual, además de las propiedades antes descritas, debe tener métodos como por ejemplo Edad(), el cual a través de la fecha de nacimiento tiene que ser capaz de calcular la edad. Esto es muy importante, ya que si las entidades las utilizamos simplemente como clases de datos estaremos cayendo en el antipatrón de modelo de datos anémico.
3.2.   Domain: En este proyecto tendremos los métodos que no se ciñen a una entidad, sino que lo hacen a varias. Es decir, operaciones que engloben varias entidades.
3.3.   Repositories: Aquí expondremos la colección de métodos que consumiremos desde nuestra capa aplication. En los repositories se va a instanciar las entidades de nuestro dominio, pero no las implementa. Para eso ya tenemos la capa de infrastructure. Por ejemplo New, Update, Delete…
 
4.      Infrastructure: Esta será la capa donde implementaremos repositorios, es decir, donde estarán las querys que ejecutaremos sobre la base de datos.
Espero haber “introducido” en esta arquitectura a gente que nunca haya trabajado con ella, y sobre todo, haber dejado claro la responsabilidad de cada una de las capas.

lunes, 8 de septiembre de 2014

La importancia de "perder" el tiempo en realizar un correcto analisis de base de datos

Hello world,

Hace tiempo que no escribo en este blog, que en su día pensé utilizar para explicar mis experiencias en el mundillo del desarrollo de aplicaciones y también como sitio donde compartir conocimiento con otros developers del mundo .NET y principalmente WEB.

El primer post de la nueva etapa va orientado a la importancia que tiene en un proyecto el realizar un buen análisis de la estructura de nuestra base de datos, tablas, naming de campos, claves, índices, etc…

La base de datos, hablando en términos de construcción, son los cimientos de la casa, si no tenemos unos buenos cimientos la casa se puede venir abajo, y tampoco vamos a empezar a construir el tejado sin haber hecho previamente los cimientos. Lo más sencillo para todo developer cuando tiene que crear una base de datos es ponerse a "picar" los create table sin haber realizado un profundo análisis de necesidades, lo cual provoca que en un corto plazo de tiempo tengas que cambiar la base de datos, desencadenando una serie de daños colaterales como pueden ser tener que cambiar las consultas, el modelo de datos de tu arquitectura, etc. Está claro, que la base de datos es una de las partes más vivas en la primera parte de desarrollo un proyecto, y que con el tiempo ésta va cambiando porque surgen nuevas necesidades, o cosas que en primer momento pensaste hacer de una cierta manera y cuando te pones a implementarlas te das cuenta que estabas equivocado.

Otro de los puntos clave en el análisis es ver las tablas que realmente necesitamos para nuestra aplicación. Tendemos a querer meter tablas para todo, muchas veces con un simple Id-Descripción que después consumimos desde una sola tabla, pero que cuando queremos obtener los datos tenemos que hace costosas joins en nuestras consultas. Este punto daría para hablar largo y tendido, ya que si somos "políticamente correctos" meteríamos tablas relacionales para todo, pero que después funcionalmente lo único que provocarían sería un desarrollo de la aplicación más lento y costoso. Así que como en todo, los extremos no son buenos, es decir, ni una tabla con 1000 campos donde está  toda la información, ni 1000 tablas con un solo campo.

El punto más dispar que me he encontrado en mi carrera profesional, es el naming de las tablas y de los campos de la base de datos. He encontrado de todo, pero principalmente 2 modelos:
  1. El equipo de desarrollo decide una nomenclatura para los campos.
  2. Se  ponen los nombres de lo que hace referencia cada cosa, siempre siguiendo unos patrones predefinidos.
El punto 1 está muy bien siempre y cuando la rotación en el equipo sea nula(algo muy difícil por no decir imposible), ya que todo el mundo estará familiarizado con dicha nomenclatura, pero desde mi punto de vista puede tener varios inconvenientes: uno seria la rotación de miembros, ya que a la que se incorporaran nuevos componentes, estos tendrían un tiempo de adaptación a esta nomenclatura. Esto podría solucionarse documentando todos y cada uno de los campos y tablas de la base de datos, pero el proyecto tendría que asumir un coste adicional para crear dicha documentación. Pero no todo es malo, esta manera de hacer los naming en la base de datos es buena si un "tercero" accede a nuestra base de datos, ya que este no sabría a qué hace referencia cada campo (tema complicado ya que se "supone" que los servidores donde se alojan las bases de datos de las aplicaciones "deben" proporcionarnos la seguridad de que nadie puede acceder a ellos. Pero esta es la teoría...).

El punto 2 facilita la compresión de nuestra base de datos, ya que de un simple vistazo se puede identificar cada campo. Pero como dije arriba, siempre hay que seguir unos patrones, y un idioma. No puede ser que haya campos que sean en inglés, otros en castellano, etc. Por ejemplo en cada tabla que tengamos un "ID", éste debe llamarse de la misma forma, no en unos sitios "id" a secas, en otros "Idxxxx", "xxxxId", etc. También otra buena práctica es poner en los campos que sean "foreing key" el nombre de la tabla a la que hace referencia. Por ejemplo si tenemos 2 tablas “Country” y "Currency", el nombre del campo foreing key de la tabla Country debería de ser CountryId.

Otro tema al cual no le solemos prestar mucha atención es los tipos de datos de los campos. Aquí hay que tener varias cosas en cuenta:
1.     Si necesitamos 10 caracteres para almacenar un valor, NO ES NECESARIO utilizar un varchar(MAX). El impacto en el rendimiento es significante si sólo hay un campo de ese tipo, pero puede convertirse en un problema cuando TODOS son así.
  1. Campos índices: SQL Server nos proporciona el tipo "autonumérico", el cual nos facilita el trabajo a los desarrolladores, pero tiene 2 inconvenientes. Uno que ese ID no es único en nuestra base de datos, con lo que no podríamos decir que un Id identifica un objeto concreto, y en cuanto al rendimiento, es más rápido para la inserción, pero más lento para la lectura (en  esto último tengo mis dudas), con lo que la solución para los campos ID es crearlo del tipo uniqueidentifier. 
Una vez tengamos nuestra base de datos creada, hay otros aspectos que debemos tener muy en cuenta si queremos ganar rendimiento en nuestra futura aplicación. El principal  es crear índices en nuestras tablas (no voy a entrar en como crearlos, ya q no es el objetivo de este post), ya que con esto se puede ganar muchísimo tiempo al realizar las consultas. Esto es algo que a primera vista piensas que no tiene por qué influir en el tiempo que emplea el motor de base de datos en devolvernos la consulta, pero en realidad tener unos buenos índices creados sobre nuestras tablas puede marcar la diferencia de tu aplicación respecto a otras. Y otro de los puntos donde se puede mejorar el rendimiento es en la manea de crear nuestra programación en la base de datos. Por ejemplo, en los "procedimientos almacenados" todos acostumbramos a crearlos como una query  que hace lo que tenga que hacer y listo, pero si en vez de hacerlo así creamos la query como un string y la ejecutamos con un sp_executesql, esto hace que la primera vez que se ejecute el procedimiento almacenado sí que pueda ser más lento, pero las siguientes ejecuciones irá mucho más rápido ya que la query se quedará cacheada en el plan de ejecución del motos de base de datos. Esto último es muy útil cuando por ejemplo tenemos que ejecutar un procedimiento almacenado varias veces. 

En conclusión, se podría decir que una de las principales cosas que hacen que un proyecto vaya bien o vaya mal es el tiempo invertido en el análisis y creación de la base de datos. Una estructuración clara y simple de la base de datos hace que nuestra arquitectura de proyecto sea más simple, con lo que será más fácil de desarrollar y sobre todo de mantener en un futuro.

 

lunes, 14 de septiembre de 2009

Cambiar estado filas de un dataSet

Hola amigos, seguro que alguna vez trabajando con dataSet habeis tenido que cambiar el estado de sus filas (RowState), pues bien, eso es asi de sencillo:

  • Cuando hemos modificado, añadido o eliminado una fila y queremos que los rowState vuelvan a ser como al principio (es decir "unchanged") solo tenemos que asignarle al dataTable lo siguiente:
    ds.Tables("MITABLA").AcceptChanges()
  • Cuando lo que queremos es poner el estado de una fila a Add o Modified solo tenemos q sobre la fila deseada hacer lo sigiente:

'Para pasar a estado added
ds.Tables("MITABLA").row(x).SetAdded()

'Para pasar a estado Modified

ds.Tables("MITABLA").row(x).SetModified()

Espero haberos servido de ayuda.

Un saludo.

jueves, 3 de septiembre de 2009

Como poner salto de linea en un alert


Hola Amigos, hoy os voy a explicar una manera sencilla de poner un salto de linea en nuestos alerts.


Esta explicación es para si el mensaje lo creamos desde codigo VB.NET o c#.NET y luego lo keremos mostrar desde javaScript.


Pues la forma es la siguiente:


  1. creamos un string con el mensaje: sStr = "Alert con un "

  2. concatenemos a ese string el siguiente valor(Chr(13)): sStr += Chr(13) -->con esto lo que hacemos es decirle que meta un intro.

  3. y por ultimo concatenamos el final del string: sStr += "salto de linea"

Codigo Resultante:


sStr = "Alert con un "


sStr += Chr(13)


sStr += "salto de linea"




Como evitar POSTBACK en TreeView


Seguramente alguna vez hayais tenido que pintar en vuestras asp un TreeView con sus respectivos nodos padre y nodos hijos(vease imagen) y os hayais encontrado con la sorpresa que al intentar desplegar un nodo padre la pagina os haya hecho PostBack, con el consiguiente perjuicio q eso genera para la web... pues bien, eso se puede controlar de una forma muy sencilla, cuando estamos añadiendo los nodos a nuestro TreeView solo es necesario informar la propiedad "SelectAction" del nodo de la siguiente manera:

nodoPadre.SelectAction = ...... (Opciones ---> Explicación)
  • TreeNodeSelectAction.Expand ---> Al dar clic se expanden los hijos, no genera postback.
  • TreeNodeSelectAction.None ---> No realiza alguna acción sobre el nodo.
  • TreeNodeSelectAction.Select ---> Selecciona el nodo, genera postback.
  • TreeNodeSelectAction.SelectExpand ---> Selecciona el nodo y expande los hijos, genera postback.

Espero que os haya servido de ayuda.

Un Saludo

NFSolutions