domingo, 21 de noviembre de 2010

Formateando que es gerundio

En muchas ocasiones es necesario formatear las entradas de datos.

Por ejemplo, algunos clientes quieren que los números se muestren con separadores decimales, otros quieren que cuando se trate de dinero se muestre además de todo lo dicho anteriormente el símbolo del euro. No debemos olvidar que para muchos clientes el la aplicación de referencia es office, así que te dirán “como en office”.

En este post no me voy a detener en como hacer la máscara, existen varias soluciones (Javascript, JQuery, Ajax.Net Control Toolkit). Lo que me resulta sorprendente es la distintas formas que me he encontrado cuando en .Net (y supongo que en Java habrá una forma similar) de dar formatos a los números o recuperar el texto de nuestro interfaz y guardarlo como número en nuestra aplicación.

Primero debemos saber como transformar un número, al formato que nos pide el cliente. He visto en muchas ocasiones como los programadores parsean de forma manual los números. Imaginemos un decimal, habría que separar la parte decimal de la parte entera, dividir de tres en tres la parte entera poniendo “.” y luego poniendo una “,” y adjuntando la parte decimal. La solución nos la da el framework en una única línea.

Supongamos que tenemos una página asp.net con una caja de texto que se llama txtMoneda en la que queremos escribir un valor numérico con el formato moneda del excel, es decir solo con dos decimales, separador de millares, separador decimal y el símbolo del euro. ¿como lo hacemos? con solo una línea:

txtMoneda.Text = initMoneda.ToString("C"); //Formato moneda


Todos los tipos numéricos tienen sobrecargado el ToString, en esta entrada de la msdn se encuentra la información necesaria.


Una vez que mostramos el texto formateado, nos falta recuperar el valor del control a nuestra variable, en este caso de tipo decimal. En .Net los tipos numéricos tienen dos métodos parse y tryparse, los dos hacen lo mismo: transforman al tipo decimal concreto. A la hora de trabajar con la capa de la vista, lo recomendable es usar tryParse. Este método solo acepta strings de entrada (que es lo que nos va a dar nuestro control), y no obtiene la cultura por defecto asi que se la tenemos que especificar, pero nos ahorramos un try para comprobar si el string de entrada.


En nuestro ejemplo para recuperar del input el valor en decimal sería algo parecido a esto:


if (!decimal.TryParse(txtMoneda.Text, NumberStyles.Number, CultureInfo.CurrentCulture, out moneda))
{
//TODO:Notificar Error
}



El enumerado NumberStyle contiene muchos estilos que se pueden utilizar de forma combinada, tal y como se muestra en su entrada de la msdn


Usando parse o tryparse, no estamos obligado a usar una mascara en nuestros controles. En nuestro ejemplo, todas esta combinaciones sería válidas:


  • 1.234,56


  • 1234,56


  • 1234


  • 1234,56 €


  • 1.234,56 €


  • 1234 €



Moraleja: para esas cosas básicas que deberían estar en el framework integradas, con casi toda seguridad lo están, consulta la msdn.

jueves, 25 de febrero de 2010

Listar Nombres de Tablas y Columnas en SQL Server

Siempre me olvido de como se listan las tablas y las columnas en SQL Server y es algo realmente útil a la hora de generar código.

Veamos como se comportan las siguientes instrucciones contra la base de datos de AdventureWorks

SELECT * FROM INFORMATION_SCHEMA.TABLES

TABLE_CATALOG TABLE_SCHEMA TABLE_NAME TABLE_TYPE
ADVENTUREWORKS Production ProductProductPhoto BASE TABLE
ADVENTUREWORKS Sales StoreContact BASE TABLE
ADVENTUREWORKS Person Address BASE TABLE
ADVENTUREWORKS Production ProductReview BASE TABLE
ADVENTUREWORKS Production TransactionHistory BASE TABLE
ADVENTUREWORKS Person AddressType BASE TABLE
ADVENTUREWORKS Production ProductSubcategory BASE TABLE
ADVENTUREWORKS dbo AWBuildVersion BASE TABLE
ADVENTUREWORKS Production TransactionHistoryArchive BASE TABLE

SELECT *

FROM INFORMATION_SCHEMA.COLUMNS

WHERE Table_Name = 'Product'

TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME ORDINAL_POSITION COLUMN_DEFAULT IS_NULLABLE DATA_TYPE
ADVENTUREWORKS Production Product ProductID 1 NULL NO int
ADVENTUREWORKS Production Product Name 2 NULL NO nvarchar
ADVENTUREWORKS Production Product ProductNumber 3 NULL NO nvarchar
ADVENTUREWORKS Production Product MakeFlag 4 ((1)) NO bit
ADVENTUREWORKS Production Product FinishedGoodsFlag 5 ((1)) NO bit
ADVENTUREWORKS Production Product Color 6 NULL YES nvarchar
ADVENTUREWORKS Production Product SafetyStockLevel 7 NULL NO smallint
ADVENTUREWORKS Production Product ReorderPoint 8 NULL NO smallint
ADVENTUREWORKS Production Product StandardCost 9 NULL NO money
ADVENTUREWORKS Production Product ListPrice 10 NULL NO money
ADVENTUREWORKS Production Product Size 11 NULL YES nvarchar
ADVENTUREWORKS Production Product SizeUnitMeasureCode 12 NULL YES nchar
ADVENTUREWORKS Production Product WeightUnitMeasureCode 13 NULL YES nchar
ADVENTUREWORKS Production Product Weight 14 NULL YES decimal
ADVENTUREWORKS Production Product DaysToManufacture 15 NULL NO int
ADVENTUREWORKS Production Product ProductLine 16 NULL YES nchar
ADVENTUREWORKS Production Product Class 17 NULL YES nchar
ADVENTUREWORKS Production Product Style 18 NULL YES nchar
ADVENTUREWORKS Production Product ProductSubcategoryID 19 NULL YES int
ADVENTUREWORKS Production Product ProductModelID 20 NULL YES int
ADVENTUREWORKS Production Product SellStartDate 21 NULL NO datetime
ADVENTUREWORKS Production Product SellEndDate 22 NULL YES datetime
ADVENTUREWORKS Production Product DiscontinuedDate 23 NULL YES datetime
ADVENTUREWORKS Production Product rowguid 24 (newid()) NO uniqueidentifier
ADVENTUREWORKS Production Product ModifiedDate 25 (getdate()) NO datetime

En el listado de columnas no he sacado todos los campos solo los primeros, porque la información que saca es muy grande, pero esta llega para hacernos una idea de lo que podemos hacer.

En el listado de tablas (como os podéis imaginar) he recortado el número de registros mostrados ;)

domingo, 21 de febrero de 2010

ObjectDataSource (I)

Cuando los controles de Microsoft hacen cosas solas les suelo llamar magia negra, ya que aunque puede llegar a ser muy potente, el desarrollador pierde el control de lo que sucede. Además es habitual que cuando es necesario hacer algo fuera de lo normal o se quita la magia negra o hay que dar muchas vueltas.

SQLDataSource es una de las magias negras más potentes de Microsoft, da soporte a un CRUD de una tabla en SQL Server y si lo enlazamos con un GridView se puede lograr el mantenimiento de los datos de una tabla sin picar una línea de código. El propio asistente del control genera las consultas necesarias para realizar las operaciones.

Esto es muy bonito, pero por debajo hace cosas que solo se deberían hacer para programar un prototipo. Toda la lógica de negocio debe de ir en la página, no hay separación entre la capa de vista y la de negocio, lo que dificulta la organización del código y evita la reutilización del mismo.

Muchos usuarios vieron que esta aproximación no cumplía sus expectativas, pero les gustaba la facilidad que este control asociado a otros les proporcionaba. Así nació el ObjectDataSource.

El ObjectDataSource es un control que se utiliza en los WebForms de asp.net para enlazar controles asociados a datos, como grids, combos. Por ejemplo la unión del ObjectDataSource con un GridView.

Pero este control tiene sus particularidades, algunas veces parece que los chicos de Redmond hacen las cosas raras. Por ejemplo, la gestión de excepciones con este control es un poco…. peculiar. El control no tienen un evento onError. Así que en los eventos Deleted, Updated, Inserted o Selected, debemos de añadir un código similar a este para manejarlo:

if (e.Exception != null)

    //Manejamos la excepción y después ponemos la siguiente
// línea para que se muestre el pantallazo con error. 
    e.ExceptionHandled = true;
}

Lo cierto es que hacer eso para cada evento es un poco coñazo, esta es una de las particularidades del ObjectDataSource