Control propio de la concurrencia en la DAL
Tras un par de meses sin apenas mover este blog, vamos a intentar darle un poco más de meneo este verano, sobre todo ahora que Carvajal tiene más tiempo para dedicarnos.
Voy a retomar la tarea comentando un repaso que ya dimos esta semana a la capa de acceso a datos para personalizar el mapeo en la clase EOrden, extendiendo la funcionalidad que ya ofrecíamos con CampoNulidad. Tuvimos que adaptar DBd para permitir esta personalización. Pero queda mucho por hacer.
Hoy me voy a centrar en una cuestión que ronda a Nibi.DAL desde que comenzamos: ¿es posible hacerlo sin DataSets? Está claro que sí, pero ¿cómo hacerlo para no perder el control de concurrecia (optimista) que nos ofrece ADO.NET? He vuelto a esta idea tras leer el artículo Introducing Custom Entity Classes, que es introductorio pero muy bueno y además argumentado, y que ofrece enlaces donde profundizar en las cuestiones más problemáticas del diseño de una capa de negocio, entre ellos el de la concurrencia ya planteado. El artículo está en ASP.NET, pero es de aplicación general, y llegué a el desde esta entrada en un blog: Article about Custom Entities vs Datasets, donde hacen una dura crítica al artículo, la cual no comparto: es cierto que puede haber entidades de negocio sobre DataSets (lo que nosotros tenemos actualmente), pero tiene bastantes contrapartidas (drawbacks):
- Ocupas más del triple de memoria: el DataSet consume bastante, y los datos están repetidos entre él y los objetos de negocio, además de que el propio DataSet los almacena dos veces: la copia actual y la de la base de datos, para ofrecer el control de concurrencia.
- Dificultas la genericidad, sobre todo a la hora de leer datos de varias entidades en una misma consulta y luego tratar de actualizar de vuelta la base de datos (un registro de la tabla del DataSet podría contener datos de varias tablas, por lo que no podrían actualizarse por separado... aquí recuerdo que el DataSet puede tener varias DataTables, pero ¿cómo cargas eficientemente en una tabla algunos albaranes y en otra sus clientes? Serían dos consultas, y la de los clientes debería incluir el mismo filtro de los albaranes... una movida que no controlo).
Volviendo al tema principal, el control de concurrencia, en Concurrency Control in ADO.NET encontramos los dos métodos de actualización optimista (lógicamente nos decantamos por optimista, eso no se merece ni media palabra más):
- Comprobar una marca de versión o fecha. Se utiliza un campo de la base de datos para almacenar, pongamos, la fecha y hora de última modificación; antes de cambiar los datos en la base de datos, comprobamos que el valor del campo en la base de datos es igual al que leímos, lo que prueba que nadie lo ha modificado; entonces guardamos cambiando la marca por una actual. La principal ventaja es el uso de memoria: no hay que guardar los datos originales, sólo un dato más. El único inconveniente es que hay que añadir un campo nuevo a la tabla.
Incluso usando DataSets, dice este artículo que tenemos que implementar nuestro propio código para emplear esta aproximación. - Comprobar todos los valores. Esta es la aproximación automática de los DataSets. En cada cambio a la base de datos, se comprueba que los valores que hay en la base de datos para TODOS los campos coincide con los que leímos nosotros. La ventaja es que es automático (en los DataSets, claro) y que no necesita nada en la tabla para funcionar. El problema es que duplica la memoria y que es más difícil de implementar.
- Si indicamos un campo especial con la fecha de actualización, se usará para comprobar al escribir, ofreciendo actualización optimista.
- Pero si para una entidad no se indica este campo, no habrá control de concurrencia, resultando en una Last In Win: el último que escribe gana, es decir, machaca los datos del anterior.
Por si no ha quedado claro, esto significa que tenemos que generar nuestras propias consultas de actualización: UPDATE, INSERT y DELETE. Hay que ver si CommandBuilder ofrece la posibilidad de ser usado para automatizar esto, devolviendo las consultas o los comandos (creo que ya esto no lo hace, así que...) y aplicando el enfoque de actualización optimista.
Por cierto, mirando todo esto he encontrado este artículo de nuestro amigo Rocky Lotcka, en el que habla de CSLA.NET. ¿A que no sabéis lo que es? Pues su propio Framework para persistencia. ¡Otro! Lo ofrece gratis (creo) pero te vende los libros en los que te enseña a manejarlo, lo cual es una muy buena práctica en mi opinión, a ver si cunde más.
De todas formas, lo he pillado en dos faltas bastante gordas:
- Dice que se pueden usar dos opciones de actualización optimista: Last In Win o First In Win (creo que esta segunda se entiende con lo que he escrito hasta ahora), y que en el libro ha usado la primera porque no tenía espacio para ponerse con la segunda, que es más compleja. En el artículo que os pongo dice que la primera opción es, literalmente, unacceptable. Hala. Así que te vende el libro usando la opción que no debe aplicarse nunca en la práctica. Está bien la cosa.
- Luego te explica esa opción más compleja, First In Win, que es básicamente lo que hacía ADO, hace ADO.NET y nos proponemos hacer nosotros mediante TimeStamp. Y al comentar cómo hacerlo comparando todos los campos, en lugar de componer una SQL que lo haga y falle si no se puede, va y te dice que antes del Update hagas un Select y compares con código propio si puedes hacer el update o no. Tiene ding dongs la cosa. De todas formas, me sigue cayendo bien este Rocky, aunque ya veo que no es muy de fiar.
Etiquetas: Nibi.Dal

1 Comments:
Reunión Pann-Berny-Carvajal:
Acordamos crear una clase EConcurrenteBase que herede de EBase aportando una nueva propiedad FechaUltimaModificacion que se persista sobre un campo TimeStamp de tipo fecha. Así las entidades que queramos que tengan control de concurrencia sólo deberán heredar de esta clase y añadir el campo con ese nombre a su tabla respectiva.
Publicar un comentario
<< Home