sábado, 29 de enero de 2011

Un error con vistas SQL

En el proyecto en el que estoy actualmente, estamos en la fase de garantía y evolutivo. Es decir, ya tenemos la aplicación en producción y ahora estamos corrigiendo los fallos encontrados, que a causa de haber echo pocos test han sido demasiados, y evolucionando según los nuevos requisitos y nuevas funcionalidades que nos pide el cliente.

Ayer, puse en producción una nueva actualización y me llevé una negativa sorpresa al saltar las alarmas en varios informes y en una página que daba un error que ni en el servidor de desarrollo, ni en el de preproducción, ni en uno de producción (son varios servidores implicados en el proyecto), se podía reproducir. Y que nos indicaba que no podía encontrar dos columnas en la tabla solicitada!!

Desesperado ante la inminente avalancha de llamadas por el bloqueo, nos revisamos el código y no localizábamos el error hasta que nos dimos cuenta que se producía en la carga de un grid por medio de un SqlDataAdapter que utilizaba un SQL que realizaba el FROM de una vista que hacia la unión entre dos tablas.

Aunque en ese momento me relaje un poquitito, ya que el problema no era de mi equipo por lo cual tampoco era nuestra responsabilidad directa, me senté igualmente con el administrador de base de datos del cliente a revisar qué le podía pasar a la vista.

La cosa se volvió extraña cuando vimos que la vista existía y era algo tal que así:

SELECT * FROM tablaA
UNION
SELECT * FROM tablaB

Revisando el historial nos dimos cuenta que habíamos modificado las tablas para añadir dos campos, justamente los que faltaban, hacia ya unas semanas. Pero mirando la vista, parecía que todo estaba correcto… pero no es así. Lanzando la vista en uno de los servidores donde fallaba nos encontramos que no incluía las columnas nuevas y las columnas de replicación (es un sistema de bases de datos sincronizadas).

A lo cual, hallamos por fin la solución al problema: BORRAS la vista –no vale con modificarla- y la vuelves a crear. Y, voala!!, todo funcionando como un tiro.

No lo he buscado en MSDN , pero supongo que SQL compila y cachea las vistas y puede, en este caso tan especial, dar este tipo de problemas.

domingo, 23 de enero de 2011

ASP.NET Login. Relacionar datos con el User.Identity

Llevo con esto del ASP desde el año 1999, y con html desde el 97. Y, aunque parezca mentira, NUNCA he utilizado el sistema de logín que trae por defecto ASP.NET. Ahora, metido en aprender MVC3 con Razor me he dado cuenta de lo cómodo que es para proyectos pequeños (y no tan pequeños) y lo estoy empezando a usar.

La duda vino cuando doy de alta al usuario, pero no sé como relacionarlo con su ficha de usuario, que está en otra tabla. Dando vueltas por San Google llegue a donde una maestro que tenemos en España. En Galicia a más señas. A Jose M. Alarcón, el cual en este post me resolvió las dudas y me abrió el camino a una clase interesantísima: Membership.

Así mi paginita de Razor para hacer la prueba a ver qué me devuelve (nombre de usuario y su ID) quedó así:

@{
MembershipUser usuario = Membership.GetUser();
}
<p>
@{
if (User.Identity.IsAuthenticated)
{
@usuario.UserName;
@usuario.ProviderUserKey.ToString();
}
}
</p>

sábado, 15 de enero de 2011

ASP.NET MVC. Error en Helper DropdownList.

Que alguien me cuente porqué cada vez que cambio de lenguaje tengo que pasar por el terrible proceso de hacer un glosario de lo que quiere decir la descripción críptica de los errores:

The ViewData item that has the key  is of type 'System.Int32' but must be of type 'IEnumerable<SelectListItem>'

Manda cojones, esto quiere decir que en el controlador no he declarado un ViewData que devuelva un ListItem para rellenar el dropdown de la vista.

            <div class="editor-field">
@Html.DropDownListFor(model => model.idClub, ViewData["Clubs"] as SelectList)
</div>



public ActionResult Edit(int id)
{
Arqueros nuevoArquero = ArquerosModel.GetArquerobById(id);

if (nuevoArquero == null)
{ return View("NotFound"); }
else
{
//Este ViewData, si no lo pones, da el precioso error de arriba.
ViewData["Clubs"] = new SelectList(ClubsModel.GetListaClubs(), "idClub", "nombre");
return View(nuevoArquero);
}
}



Ale, supongo que de este tipo de entradas voy a ir metiendo unas cuantas.

jueves, 13 de enero de 2011

asp.net MVC 3.0 EF4 DELETE y UPDATE

Vaya título me ha salido!!

Haciendo mi primera aplicación CRUD en MVC 3.0 + Entity Framework 4.0 me encuentro que hay montones de ejemplos de listado e inserción de registros pero la cosa se empieza liar un poquillo con borrado y bastante más con actualización.

Como el problema no están en el controlador ni en la vista, si no en el modelo y en los métodos que hay que construir para hacer ambas acciones (y de lo que no hay información en castellano, o no la he encontrado en Google), aquí las pongo. Que son ligeramente diferentes que en linq to sql.

        internal static void Delete(Clubs club)
{
ArqueriaModelContainer arqueriaContext = new ArqueriaModelContainer();
arqueriaContext.AttachTo("Clubs", club);
arqueriaContext.DeleteObject(club);
}

internal static void ActualizaClub(Clubs Club)
{
ArqueriaModelContainer arqueriaContext = new ArqueriaModelContainer();
arqueriaContext.AttachTo("Clubs", Club);
arqueriaContext.ObjectStateManager.ChangeObjectState(Club, EntityState.Modified);
arqueriaContext.SaveChanges();
}


Como habrás notado, mi aplicación se centra en la gestión de arqueros y estos dos métodos borran y modifican un club. Por lo cual tengo objetos del tipo Clubs –que es una entidad que mapea la tabla Clubs – y el contexto llamado ArqueriaModelContainer.



Cosas interesantes. Que como lo que me traigo es una entidad sin enlazar con el contexto, lo primero que hay que hacer es enlazarla con el método attach. A continuación puedes borrarla directamente, o cambiarle el estado de la entidad a modificado para poder salvar los cambios.



Cosa que no hay que hacer, declarar una propiedad de la clase que instancie el contexto, porque da problemas al intentar enlazar una entidad que ya está enlazada, en el caso de la actualización. Supongo que con tiempo para darle vueltas y refactorizando, se puede hacer mucho mejor.



Pero cómo obtengo la entidad Club de la vista. Pues un poco de magia de MVC que no tengo claro aún cómo lo hace pero en el controlador tengo este código:



public ActionResult Edit(int id)
{
Clubs club = ClubsModel.GetClubById(id);
if (club == null)
{ return View("NotFound"); }
else
{ return View(club); }
}
[HttpPost]
public ActionResult Edit(Clubs club)
{
ClubsModel.ActualizaClub(club);
return RedirectToAction("Index");
}


En la primera parte recupera de la queryString el id del Club que quiero modificar y le envío la entidad entera por la vista. En la segunda parte, recupero la entidad que he enviado en la primera. Si, entera y sin tener que hacer tediosas cargas del contenido de los controles en los campos de la entidad. El código en la página Razor se obtiene de forma tan simple como, pulsando con el botón derecho en el segundo ActionResult, decirle que quieres una vista fuertemente tipada con la plantilla de edit.



@model Arqueria.Models.Clubs
@{
Layout = null;
}
<!DOCTYPE html>
<
html>
<
head>
<
title>Edit</title>
</
head>
<
body>
@using (Html.BeginForm()) {
<fieldset>
<
legend>Clubs</legend>
@Html.HiddenFor(model => model.idClub)
<div class="editor-label">
@Html.LabelFor(model => model.nombre)
</div>
<
div class="editor-field">
@Html.EditorFor(model => model.nombre)
@Html.ValidationMessageFor(model => model.nombre)
</div>
<
div class="editor-label">
@Html.LabelFor(model => model.identificador)
</div>
<
div class="editor-field">
@Html.EditorFor(model => model.identificador)
@Html.ValidationMessageFor(model => model.identificador)
</div>
<
div class="editor-label">
@Html.LabelFor(model => model.domicilio)
</div>
<
div class="editor-field">
@Html.EditorFor(model => model.domicilio)
@Html.ValidationMessageFor(model => model.domicilio)
</div>
<
div class="editor-label">
@Html.LabelFor(model => model.cp)
</div>
<
div class="editor-field">
@Html.EditorFor(model => model.cp)
@Html.ValidationMessageFor(model => model.cp)
</div>
<
div class="editor-label">
@Html.LabelFor(model => model.localidad)
</div>
<
div class="editor-field">
@Html.EditorFor(model => model.localidad)
@Html.ValidationMessageFor(model => model.localidad)
</div>
<
div class="editor-label">
@Html.LabelFor(model => model.provincia)
</div>
<
div class="editor-field">
@Html.EditorFor(model => model.provincia)
@Html.ValidationMessageFor(model => model.provincia)
</div>
<
p>
<
input type="submit" value="Save" />
</
p>
</
fieldset>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
</
body>
</
html>


Por razones de longitud del post, no pongo la página index, que es el mero listado de los clubs.

Espero que le sea de utilidad a alguien más que a mi.

miércoles, 12 de enero de 2011

Cuando nos olvidamos del “Test vacío”

El nivel de trabajo ha vuelto a la normalidad después de una entrega en producción bastante menos limpia de lo que hubiera querido o, aún peor, esperado. Se ha cumplido a rajatabla el lema de que el código tiene la calidad de los miembros del equipo. Con tres noveles, aunque uno de ellos tenga bastante talento, la cosa ha salido como ha salido y aún así ha salido bastante bien.

Por lo cual he tenido tiempo de ver mil blogs que no había tenido tiempo para leer, y acceder al código de dos pseudogurus y un compañero de alt.net que, puedo estar seguro,  tienen un nivel como desarrolladores mucho mayor que el mío. Al menos en la teoría.

Dicho código es la nueva moda en el mundo del desarrollo “güay” que son la Katas, abanderadas por Uncle Bob (creo), y que a mi no me termina de dar confianza la llamada conexión entre ellas y la mejora en la calidad del código que hacemos. ¿Practicando muchísimos saques terminamos jugando mejor al tenis?¿Haciendo muchas veces escalas cromáticas podemos componer mejor?

Y en los tres casos me encuentro que tres profesionales (más bien cuatro ya que uno es un equipo de dos) con mucha experiencia han caído en el error de novato de no hacer el “test de vacío”. Es decir, hago una clase sencillita, me centro en TDD, me centro en un código fluido, autoexplicativo, en una refactorización super chula, ajustado a SOLID y DRY… y se me olvida gestionar si el parámetro de entrada llega nulo. Y todo el trabajo realizado se queda en un bonita rotura de la aplicación con una excepción de objeto nulo.

Vamos, me digo, pero si es un error de novato. Es lo primero que aprendí, justo después de apretar el botón de enviar de un formulario con todos los campos vacíos. Y la siguiente pregunta es más preocupante, ¿estamos perdiendo en la comunidad de desarrollo el foco? ¿Nos centramos en las cosas de “alto nivel” y olvidamos lo realmente importante, “hacer software que funciona”. ?

Moraleja, trabajar con novatos te hace volver la mirada a las cosas que los clientes quieren, que es que las cosas funcionen.

martes, 4 de enero de 2011

Hoy le he visto la cara al futuro en la cloud

Estoy sentado en una silla en la oficina de la ISS (antigua seguridad social) esperando a que pasen casi 80 personas que están por delante mío para solucionar un lio con el número de mi hija.

Mientras, me conecto con mi mobile 6.0 a la web del ministerio de justicia y pido un certificado literal de nacimiento de mi madre al registro civil de Barcelona. La alarma de baja batería salta y abro el portátil para recargarlo y aumentar el exiguo 9% que me queda.

Y me he gastado la batería conectándome a google maps para ir localizando las calles a donde voy de salto en salto siguiendo las indicaciones erróneas de funcionarios que no tienen claro donde se realiza la solicitud de este certificado que al final he pedido por la oficina virtual.  Si una calle me hubiera dado problemas, me hubiera conectado con el receptor de gps, y que el tomtom me hubiese llevado de la mano.

¿Cuando he visto el futuro? Cuando he abierto el portátil para aprovechar las casi 40 personas que me quedan delante para adelantar trabajo, y me he dado cuenta que aquí no hay wifi y que no tengo configurado el móvil como modem 3G… y al percatarme que la mayoría de mis documentos están en mi buzón de correo, tanto el del trabajo como los míos personales, que están situados en la cloud. Uno en nuestros servidores a los que accedo con un cliente webmail, y otros en el cloud de google.

Es más, me he dado cuenta que el futuro ya está aquí cuando mi primer impulso no es lamentarme por no tener una copia local de mi información en este portátil, si no que me lamento de no tener configurado mi móvil. Me lamento de no poder acceder a Internet y la Cloud en donde tengo mi información sensible. Y me doy cuenta que estoy en el futuro. Que mi información no es mía, y que no me importa lo más mínimo. Pero si que me importa, y mucho, el poder acceder a ella desde cualquier sitio y en cualquier momento.

Y se me plantean nuevas necesidades que se convierten en prioritarias… ¿cómo hago un backup de mis datos?¿Qué dispositivo puede almacenar tanta información?¿Cómo lo mantengo sincronizado?¿Qué tan segura es la Cloud? Y no hablo de seguridad de acceso a mis datos, si no a seguridad física. Que mañana una catástrofe política, natural o económica no tenga como posibilidad la pérdida de mis múltiples repositorios virtuales.

Interesante futuro… me gusta.