concurrencia en ado.net

8
dotNetManía < < 20 cual es esa problemática y posteriormente qué alternativas tenemos para tratarla. El problema fundamental que se nos plantea son los conflictos de concurrencia. Un conflicto de concurrencia se produce cuando un usuario modifica un registro de una tabla de una base de datos y ese registro ha cambiado desde la última vez que lo leyó. Por ejemplo, conside- remos la siguiente secuencia de sucesos: Los usuarios A y B leen el registro R1 de la base de datos cargándolo en un DataSet. El usuario A modifica R1 El usuario A guarda R1 en la base de datos. El usuario B modifica R1 El usuario B guarda R1 en la base de datos. El usuario B recibe una excepción DBConcurrencyException, indicando un con- flicto de concurrencia al haber sido modi- ficado R1 desde la última vez que B lo leyó. Los conflictos de concurrencia no se produ- cen solamente al actualizar un registro porque otro usuario lo haya modificado, también ocu- rren si el registro ha sido eliminado por otro usua- rio. Asimismo, tienen lugar cuando un usuario intenta eliminar un registro que ha sido modifi- cado e incluso que ha sido eliminado. Con la inserción, sin embargo, es evidente que no se pro- ducen conflictos de concurrencia, ya que es impo- sible que otro usuario pueda modificar un regis- tro que aún no existe en la base de datos. En defi- nitiva, los conflictos de concurrencia pueden pro- ducirse: Al modificar un registro Al eliminar un registro Y la causa del conflicto puede ser porque dicho registro: Ha sido modificado desde la última vez que se leyó. Ha sido eliminado desde la última vez que se leyó. Otro aspecto básico acerca de los conflictos de concurrencia es la forma de detectarlos. La técnica de detección se basa fundamentalmente en incluir en la cláusula WHERE de la instruc- ción UPDATE o DELETE el valor original de los campos, es decir, el valor que tenían los cam- pos del registro cuando se leyeron de la base de datos. Pongamos un ejemplo para aclarar ideas. Gestión de concurrencia en ADO.NET Por Jesús López Méndez (SqlRanger) La concurrencia, en un entorno multiusuario, es siempre una cuestión proble- mática, pero si además se trata de un entorno desconectado como el que se usa en ADO.NET con sus DataSets y DataAdapters,la problemática es aún mayor debido a la propia naturaleza desconectada del entorno. Veamos,en primer lugar, < <

Upload: simon-camacho

Post on 14-Dec-2014

21 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Concurrencia en Ado.net

dotN

etM

anía

<<

20

cual es esa problemática yposteriormente qué alternativas tenemos paratratarla. El problema fundamental que se nosplantea son los conflictos de concurrencia. Unconflicto de concurrencia se produce cuando unusuario modifica un registro de una tabla de unabase de datos y ese registro ha cambiado desdela última vez que lo leyó. Por ejemplo, conside-remos la siguiente secuencia de sucesos:

• Los usuarios A y B leen el registro R1 dela base de datos cargándolo en un DataSet.

• El usuario A modifica R1• El usuario A guarda R1 en la base de datos.• El usuario B modifica R1• El usuario B guarda R1 en la base de datos.

• El usuario B recibe una excepciónDBConcurrencyException, indicando un con-flicto de concurrencia al haber sido modi-ficado R1 desde la última vez que B lo leyó.

Los conflictos de concurrencia no se produ-cen solamente al actualizar un registro porqueotro usuario lo haya modificado, también ocu-rren si el registro ha sido eliminado por otro usua-rio. Asimismo, tienen lugar cuando un usuariointenta eliminar un registro que ha sido modifi-cado e incluso que ha sido eliminado. Con lainserción, sin embargo, es evidente que no se pro-ducen conflictos de concurrencia, ya que es impo-sible que otro usuario pueda modificar un regis-tro que aún no existe en la base de datos. En defi-nitiva, los conflictos de concurrencia pueden pro-ducirse:

• Al modificar un registro• Al eliminar un registro

Y la causa del conflicto puede ser porquedicho registro:

• Ha sido modificado desde la última vez quese leyó.

• Ha sido eliminado desde la última vez quese leyó.

Otro aspecto básico acerca de los conflictosde concurrencia es la forma de detectarlos. Latécnica de detección se basa fundamentalmenteen incluir en la cláusula WHERE de la instruc-ción UPDATE o DELETE el valor original delos campos, es decir, el valor que tenían los cam-pos del registro cuando se leyeron de la base dedatos. Pongamos un ejemplo para aclarar ideas.

Gestión de concurrencia en ADO.NET

Por Jesús López Méndez(SqlRanger)

La concurrencia, en un entorno multiusuario, es siempre una cuestión proble-mática, pero si además se trata de un entorno desconectado como el que seusa en ADO.NET con sus DataSets y DataAdapters, la problemática es aún mayordebido a la propia naturaleza desconectada del entorno.

Veamos, en primer lugar,<<

Page 2: Concurrencia en Ado.net

Supongamos que estamos trabajandocon la siguiente tabla en una base dedatos de SQL Server:

El comando UPDATE que detec-ta conflictos de concurrencia sería elsiguiente:

Como veis, están todos los valoresoriginales en la cláusula WHERE deesta instrucción parametrizada. Deesta manera, si ha cambiado algunode los campos, no se cumplirá la con-dición, y por tanto la instrucción noactualizará ningún registro, o lo quees lo mismo, el número de registrosafectados será cero. Solamente la ins-trucción tendrá éxito, o sea, actuali-zará el registro, si éste no ha cambia-do. Así es como ADO.NET detectalos conflictos de concurrencia, con-cretamente un DataAdapter lanzaráuna excepción DBConcurrencyExceptioncuando el comando de actualizaciónafecte a cero registros. Observad queeste comando incluye todos los cam-

pos en la cláusula SET, excepto elIdEmpleado que es autonumérico y portanto de sólo lectura. Esto viene a

suponer que se actualizarán todos loscampos en la tabla, independiente-mente de si se han modificado o no,

lo que implica una falta de optimiza-ción.

Sin embargo, es posible que no nosinterese detectar conflictos de concu-rrencia y que queramos que la actua-lización se lleve a cabo independien-temente de si el registro ha sido modi-ficado o no desde la última vez que seleyó. En ese caso sólo incluiríamos laclave primaria en la cláusula WHERE.La instrucción UPDATE sería lasiguiente:

Aún así, podríamos obtener unconflicto de concurrencia, pero sóloen el caso de que haya sido eliminadoel registro. Un inconveniente de estaopción es que es posible perder modi-ficaciones. Si por ejemplo, los usua-rios A y B leen el empleado 10, elusuario A modifica su nombre y loguarda, y luego B modifica el apelli-do y lo guarda, las dos actualizacionestienen éxito, pero la modificación quehizo A se pierde, ya que el nombre essobrescrito con el valor que leyó B.En ciertos sistemas, esta posible pér-dida de modificaciones es inaceptabley por tanto habría que elegir otraopción.

Otra alternativa sería incluir en lacláusula SET sólo los campos que sehan modificado. De esta manera, aun-que sólo incluyéramos la clave pri-maria en la cláusula WHERE, no seperderían las modificaciones. Tambiénes una opción interesante incluir enla cláusula SET sólo los campos modi-ficados, y en la cláusula WHERE laclave primaria más el valor original delos campos que han cambiado, así elconflicto de concurrencia que detec-taríamos sería en el caso de que otrousuario hubiera modificado alguno delos campos que han sido modificadoso en el caso de eliminación. Por ejem-plo, si los usuarios A y el B leen elempleado 10, el usuario A modifica su

nombre y lo guarda y el usuario Bmodifica su nombre y lo guarda, elusuario B recibe un conflicto de con-currencia. Pero si lo que ocurre es queel usuario A modifica el nombre y elB el apellido, no hay conflicto de con-currencia y las dos actualizaciones tie-nen éxito.

Una última alternativa para la cláu-sula WHERE es incluir la clave pri-maria más el valor original de un cam-po de tipo TimeStamp que por supues-to tendría que formar parte de la tabla.El funcionamiento es equivalente aincluir los valores originales de todos

dotN

etM

anía

<<

21

dnm.plataforma.ado.net<<

CREATE TABLE Empleados (IdEmpleado INT IDENTITY(1,1) PRIMARY KEY,DNI VARCHAR(12) NOT NULL UNIQUE,Nombre VARCHAR(50) NOT NULL,Apellidos VARCHAR(50) NOT NULL

)

UPDATE EmpleadosSET DNI=@DNI, Nombre=@Nombre, Apellidos=@ApellidosWHERE IdEmpleado=@Original_IdEmpleado AND DNI=@Original_DNI AND

Nombre=@Original_Nombre AND Apellidos=@Original_Apellidos

UPDATE EmpleadosSET DNI=@DNI, Nombre=@Nombre, Apellidos=@ApellidosWHERE IdEmpleado=@Original_IdEmpleado

Los conflictos de concurrencia no se producen solamente al actualizar un registro porque otro usuario

lo haya modificado, también ocurren si el registro ha sido eliminado por otro usuario

Page 3: Concurrencia en Ado.net

dotN

etM

anía

<<

22

dnm.plataforma.ado.net<<

los campos, pero resulta más eficiente ya que la ins-trucción es más corta, reduciéndose el tráfico dered y reduciendo el trabajo del procesador de con-sultas del servidor de base de datos. Un campo detipo TimeStamp en SQL Server es una especie deautonumérico de 64 bits único en toda la base dedatos. No puede haber dos registros en una base de

datos con el mismo valor de TimeStamp, inclusoaunque pertenezcan a distintas tablas. Cada vez quese modifica un registro que tiene un campoTimeStamp, el valor del campo también cambia.Debido a esto y si usamos esta alternativa, despuésde modificar un registro, sería necesario volver aleer el campo TimeStamp para poder realizar másmodificaciones en el mismo registro.

Detectar conflictos de concurrencia en la eli-minación es similar a la actualización, con la salve-dad de que en este caso sólo podemos jugar con lacláusula WHERE de la instrucción DELETE.Podríamos incluir sólo la clave primaria, en cuyocaso sólo obtendremos conflictos de concurrenciacuando otro usuario haya eliminado el registro. Enla mayoría de los casos, este conflicto sencillamen-te lo podríamos ignorar. También podríamos incluirtodos los valores originales de los campos o la cla-ve primaria más el TimeStamp, en cuyo caso reci-biremos un conflicto de concurrencia cuando otrousuario haya modificado o eliminado el registro.

Una vez que tenemos decidido cómo vamos adetectar los conflictos de concurrencia y cómovamos a hacer las actualizaciones y eliminaciones,hemos de decidir cómo los vamos a tratar, o sea,qué acciones vamos a tomar en el caso de un con-flicto de concurrencia. Cada conflicto de concu-rrencia lo trataremos de manera diferente en fun-ción de si se ha producido al hacer una actualiza-ción o al realizar una eliminación y en función dela causa del conflicto, esto es, si ha sido porqueotro usuario lo ha modificado o porque lo ha eli-minado.

Empecemos primero por los conflictos que seproducen al actualizar. Si la causa es que otro usua-rio lo ha modificado podríamos tener las siguien-tes alternativas:

• Descartar las modificaciones y refrescar el registrovolviéndolo a leer de la base de datos. Al usuariole avisaríamos del conflicto de concurrencia yle daríamos la oportunidad de volver a hacerlas modificaciones.

• Refrescar sólo los valores originales sin descartar lasmodificaciones. Al usuario le avisaríamos del con-flicto. Entonces él tendría la oportunidad dever las modificaciones deshaciendo cambios ode volver a guardar con lo que forzaría la actua-lización.

• Directamente forzar la actualización. Esto seconoce como la técnica “el último que llegagana”. En realidad esta acción no es una res-puesta a un conflicto de concurrencia, ya quepara llevarla a cabo incluiríamos únicamentela clave primaria en la cláusula WHERE, nodetectándose conflictos de concurrencia pormodificación.

Si la causa es que otro usuario lo ha eliminado,las alternativas serían las siguientes:

• Volver a insertar el registro en la base de datos. Enel caso de que tengamos un autonumérico enla tabla no sería posible volver a insertar elregistro exactamente igual a como era ante-riormente.

• Eliminarlo del DataSet. Esta es la opción quemás se suele utilizar.

Detectar la causa del conflicto, al igual querefrescar un registro, puede realizarse volviendo aleer tal registro de la base de datos basándose en laclave primaria, pero si la clave primaria puede cam-biar, esta técnica no sirve para su propósito ya quesi ésta ha cambiado no es posible identificar el regis-tro y no es posible determinar si el conflicto de con-currencia ha ocurrido por modificación o por eli-minación. Por eso sería recomendable usar clavesprimarias artificiales como autonuméricos oGUID’s.

En cuanto a los conflictos de concurrencia quese producen al eliminar un registro, podríamos tenerlas siguientes alternativas cuando la causa es pormodificación:

• Deshacer la eliminación y refrescar el registro. Alusuario le informaríamos del conflicto y ten-dría la posibilidad de volverlo a eliminar des-pués de haber visto los cambios realizados.

La técnica de detección se basa fundamentalmente en incluir en la cláusula WHERE

de la instrucción UPDATE o DELETE el valor original de los campos

Page 4: Concurrencia en Ado.net

• Forzar la eliminación. En realidadesta acción no es una respuesta aun conflicto de concurrencia, yaque para llevarla a cabo incluiría-mos únicamente la clave primariaen la cláusula WHERE con lo queno se detectan conflictos de con-currencia por modificación.

Por último, el conflicto de concu-rrencia que se produce al eliminar unregistro que ha sido eliminado, gene-ralmente puede tratarse sencillamen-te ignorando el conflicto y eliminan-do definitivamente el registro delDataSet.

Como hemos visto, existen variasalternativas para detectar y tratar losconflictos de concurrencia. Veamosahora qué nos ofrece ADO.NET eneste sentido.

En ADO.NET tenemos una seriede clases, los DataAdapters, que sonlos encargados de revertir las modi-ficaciones realizadas en un DataSetsobre la base de datos mediante sumétodo Update. Los DataAdapters tie-nen tres propiedades: DeleteCommand,UpdateCommand e InsertCommand queson los comandos de actualización.Estos comandos son parametrizados,de manera que sirvan para todas las filasde un DataTable. Cuando invocamos almétodo Update de un DataAdapter, ésterecorre todas las filas del DataTable, ysi la fila es una fila eliminada, ejecutael DeleteCommand; si la fila es una filamodificada, invoca el UpdateCommand;y si es una fila nueva, invoca alInsertCommand. Si al invocar al Update-Command o al DeleteCommand, elnúmero de registros afectados es cero,el DataAdapter lanza una excepciónDBConcurrencyException indicando quese ha producido un conflicto de con-currencia. Antes de invocar un coman-do de actualización, el DataAdapterestablece el valor de los parámetros delcomando con los valores originales oactuales de los campos de la fila basán-dose en la configuración del propiocomando. Cada parámetro de la colec-ción Parameters de un comando tienela propiedad SourceColumn que indicael nombre del campo cuyo valor debe-rá copiarse al parámetro, y la propie-dad SourceVersion que indica si se trata

del valor actual o del valor original.Antes de poder invocar al métodoUpdate de un DataAdapter tenemosque configurarlo correctamente, estoes, tenemos que establecerle loscomandos de actualización. Para con-figurar un DataAdapter tenemos tresalternativas:

• Usar el asistente para la configu-ración del DataAdapter

• Usar un CommandBuilder• Configurarlo manualmente

escribiendo nosotros mismos elcódigo

Para usar el asistente, sólo tene-mos que arrastrar un DataAdapterde la ficha datos del cuadro deherramientas a nuestro formularioo componente y seguir sus instruc-ciones. En el paso “Generar las ins-trucciones SQL” tenemos un botón“Opciones avanzadas” que nos pre-

senta el cuadro de diálogo de lafigura 1.

Como vemos, el asistente puedegenerar por nosotros los comandos deactualización INSERT, UPDATE yDELETE. Si elegimos “Usar concu-rrencia optimista”, el asistente inclui-rá en la cláusula WHERE de las ins-trucciones UPDATE y DELETE elvalor original de todos los campos delregistro. Mientras que si no activamosesa casilla de verificación, la cláusulaWHERE sólo incluirá la clave prima-ria. Si elegimos “Actualizar el con-junto de datos” el asistente añade unainstrucción SELECT a los comandosde actualización para refrescar el regis-tro. En cualquier caso, la instrucciónUPDATE incluye en la cláusula SETtodos los campos.

Esta sería la instrucción UPDA-TE para nuestra tabla de ejemplousando concurrencia optimista. Vertabla 1.

dotN

etM

anía

<<

23

dnm.plataforma.ado.net<<

Figura1. Opciones avanzadas de generación de instrucciones SQL.

UPDATE EmpleadosSET DNI=@DNI, Nombre=@Nombre, Apellidos=@ApellidosWHERE IdEmpleado=@Original_IdEmpleado AND DNI=@Original_DNI AND

Nombre=@Original_Nombre AND Apellidos=@Original_Apellidos

Tabla 1

Page 5: Concurrencia en Ado.net

dotN

etM

anía

<<

24

dnm.plataforma.ado.net<<

Y esta sería la instrucción UPDATE sin usar laconcurrencia optimista:

Como hemos dicho anteriormente, tambiénpodemos usar un CommandBuilder. Este sería elcódigo a usar para nuestra tabla de ejemplo:

Las instrucciones UPDATE y DELETE seríanequivalentes a las generadas por el asistente usan-do concurrencia optimista y sin actualizar el con-junto de datos.

La alternativa de configurar manualmente elDataAdapter no es muy recomendable, ya querequiere escribir bastante código y la funcionalidadobtenida es exactamente igual a la conseguida usan-do el asistente. Además es posible que cometamosalgún error al escribir el código, mientras que elasistente no los comete.

Como vemos, el DataAdapter sólo nos deja la posi-bilidad de incluir en la cláusula WHERE de las ins-trucciones UPDATE y DELETE o bien la clave pri-maria, o bien todos los campos. No tenemos las otrasalternativas que se mencionan en este artículo. Ademásen la cláusula SET de la instrucción UPDATE, sólopodemos incluir todos los campos, no tenemos laopción de incluir sólo los modificados.

Por otra parte, ADO.NET sólo da soporte parala detección del conflicto de concurrencia, no haynada que nos ayude a gestionarlo, por lo que ten-dremos que escribir nosotros mismos el códigonecesario.

El código de ejemplo del fuente 1 muestra comogestionar conflictos de concurrencia, refrescandoel registro si ha sido modificado y eliminándolo siha sido eliminado.

Como vemos, gestionar los conflictos de concu-rrencia no es trivial y repetir el mismo código una yotra vez para cada caso es muy laborioso y pesado.

Una buena alternativa a los DataAdapters que vie-nen incluidos en .NET Framework, es escribir nues-tro propio DataAdapter que no tenga estas limita-

ciones, que sea capaz de gestionar los conflictos deconcurrencia y que disponga de todas las opciones

mencionadas en este artículo. Podéis encontrar unDataAdapter para SQL Server (SqlRanger.SqlAdapter)escrito por mí en la web de la revista o en mi propiapágina web: http://sqlranger.com/descargas.aspx.

Este DataAdapter es completamente gratis y seincluye el código fuente así como un ejemplo de suuso. El SqlRanger.SqlAdapter tiene propiedades espe-cíficas para tratar la concurrencia. Entre las que seincluyen:

• UpdateCriteria: Determina los campos a incluiren la cláusula WHERE de la instrucciónUPDATE. Puede tomar los siguientes valores:• All: Se incluirán los valores originales de

todos los campos.• Key: Se incluirá sólo la clave primaria.• Modified: Se incluirá la clave primaria más

los valores originales de los campos modi-ficados.

• TimeStamp: Se incluirá la clave primaria másel valor original del campo TimeStamp si esque existe.

• UpdateColumns: Determina qué campos apa-recerán en la cláusula SET de la instrucciónUPDATE. Puede tomar los siguientes valores:• All: Se incluyen todos los campos.• Modified: Se incluyen sólo los campos modi-

ficados.

• DeleteCriteria: Determina los campos a incluiren la cláusula WHERE de la instrucción DELE-TE. Puede tomar los siguientes valores:• All: Se incluirán los valores originales de

todos los campos.• Key: Se incluirá sólo la clave primaria.• TimeStamp: Se incluirá la clave primaria más

el valor original del campo TimeStamp si esque existe.

UPDATE EmpleadosSET DNI=@DNI, Nombre=@Nombre, Apellidos=@ApellidosWHERE IdEmpleado=@Original_IdEmpleado

SqlDataAdapter Adapter = new SqlDataAdapter(“SELECT * FROM Empleados”, Connection);SqlCommandBuilder CommandBuilder = new SqlCommandBuilder(Adapter);Adapter.UpdateCommand = CommandBuilder.GetUpdateCommand();Adapter.InsertCommand = CommandBuilder.GetInsertCommand();Adapter.DeleteCommand = CommandBuilder.GetDeleteCommand();

Page 6: Concurrencia en Ado.net

dotN

etM

anía

<<

25

dnm.plataforma.ado.net<<

public void Guardar(DataTable Empleados){

// creamos un adapter para realizar la actualizaciónSqlDataAdapter Adapter = new SqlDataAdapter(“SELECT * FROM Empleados”, this.cn);

// usamos un command builder para configurar los comandos de actualizaciónSqlCommandBuilder CommandBuilder = new SqlCommandBuilder(Adapter);Adapter.UpdateCommand = CommandBuilder.GetUpdateCommand();Adapter.InsertCommand = CommandBuilder.GetInsertCommand();Adapter.DeleteCommand = CommandBuilder.GetDeleteCommand();

// este comando nos sirve para refrescar un registroSqlCommand Resync = new SqlCommand(“SELECT * From Empleados WHERE IdEmpleado=@IdEmpleado”, this.cn);Resync.Parameters.Add(“@IdEmpleado”, SqlDbType.Int);

try{

Adapter.Update(Empleados);}catch ( DBConcurrencyException ex ){

// Nuestra respuesta a un conflicto va a ser refrescar el registroAdapter.SelectCommand = Resync;Resync.Parameters[“@IdEmpleado”].Value = ex.Row[“IdEmpleado”, DataRowVersion.Original];

// el método Fill buscará el registro en el DataTable // por clave primaria (IdEmpleado) y lo “refrescará”if ( Adapter.Fill(Empleados) == 0 ) // la causa del conflicto es que ha sido eliminado (Fill devuelve cero registros){

if ( ex.Row.RowState == DataRowState.Deleted ){

// en este punto tenemos un conflicto de concurrencia// al eliminar un registro porque ha sido eliminado.

// Eliminamos definitivamente el registroex.Row.AcceptChanges();// ignoramos el conflicto y seguimos con la actualizaciónGuardar(Empleados);

}else{

// en este punto tenemos un conflicto de concurrencia// al modificar un registro porque ha sido eliminado

// Eliminamos el registro // y volvemos a lanzar la excepciónex.Row.Delete();ex.Row.AcceptChanges();throw ex;

}}else{

// la causa del conflicto es que ha sido modificado

// Si el conflicto ha sido al eliminar el registro// Fill ya lo habrá “recuperado” y refrescado. // Aparecerá el registro con el error

// Si el conflicto ha sido al modificar el registro// Fill lo habrá “refrescado”. Y aparecerá el registro // con el error

// sólo hay que volver a lanzar la excepciónthrow ex;

}}

}

Fuente 1. Ejemplo de gestión de conflictos de concurrencia

Page 7: Concurrencia en Ado.net

dotN

etM

anía

<<

26

dnm.plataforma.ado.net<<

• ConflictUpdatingChangedAction:Determina la acción a realizar encaso de un conflicto de concu-rrencia al actualizar un registroporque haya sido modificado des-de la última vez que se leyó. Puedetomar los siguientes valores:• NoAction: No hace nada.• ResyncAllValues: Refresca todos

los valores del registro, volvién-dolo a leer de la base de datos.

• ResyncOriginalValues: Refresca losvalores originales del registro,leyéndolo de la base de datos.

• ConflictUpdatingDeletedAction:Determina la acción a realizar encaso de un conflicto de concurren-cia producido al actualizar un regis-tro porque haya sido eliminado des-de la última vez que se leyó. Puedetomar los siguientes valores:

• Delete: Elimina definitivamen-te el registro del DataSet.

• Insert: Vuelve a insertar el re-gistro en la base de datos.

• NoAction: No hace nada.

• ConflictDeletingChangedAction:Determina la acción a realizar encaso de un conflicto de concu-rrencia producido al eliminar unregistro porque haya sido modi-ficado desde la última vez que seleyó. Puede tomar los siguientesvalores:• NoAction: No hace nada.• ResyncAllValues: Refresca el

registro, volviéndolo a leer dela base de datos.

• ResyncCommand: Comandoparametrizado basado en cla-ve primaria utilizado pararefrescar un registro.

El SqlRanger.SqlAdapter genera auto-máticamente los comandos de actualiza-ción y el ResyncCommand, no siendo nece-sario proporcionárselos. Para ello haceuso del SqlRanger.CommandBuilder.

ConclusiónLa concurrencia es un tema proble-

mático en ADO.NET dada su natura-leza desconectada. Existen varias opcio-nes para detectar y tratar los conflictosde concurrencia. Cada una de estasopciones tiene sus ventajas e inconve-nientes y es necesario elegir cuidadosa-mente la más adecuada para el sistemaen cuestión. ADO.NET da soportelimitado para la gestión de la concu-rrencia, siendo una buena alternativaescribir nuestro propio DataAdapter parasuperar las limitaciones.

noticias.noticias.noticias.noticias

¿Qué es Whitehorse?Whitehorse es el nombre en clave del software que se incluirá en

Visual Studio 2005 y que aporta herramientas de diseño model-drivendirigida a los arquitectos de software, enlazando el modelo conceptualal código.

Tendremos más información en el devdays que se celebrará en San Diego,California entre el 23 y el 28 de Mayo (http://www.microsoft.com/semi-nar/teched2004). En Europa se celebrará en Ámsterdam, Holanda, entre el29 de Junio y el 2 de Julio (http://www.microsoft.com/europe/teched).

Entretanto puede descargarse un video demostrativo de la web deMSDNTV en http://msdn.microsoft.com/msdntv

¿Qué es Laguna?En el Microsoft Mobile DevCon Conference 2004 celebrado en

San Francisco entre el 23 y el 27 de marzo se habló de “Laguna”, nom-bre en clave del SQL Server CE 3.0. Esta versión se verá retrasada igualque la versión completa, el SQL Server 2005. Según nuestras noticias,ambas versiones saldrán juntas, si bien la versión beta 1 de Laguna esta-rá disponible cuando esté la beta 2 de Yukon.

La web del Mobile DevCon Conference 2004 está en:http://www.microsoftmdc.com.

Puede ver información de la versión actual de SQL Server CE 2.0en: http://www.microsoft.com/sql/ce.

¿Qué es Indy?Indy es el nombre en clave de una nueva herramienta de gestión

desarrollada por Microsoft Research y que se comercializará por la divi-sión Enterprise Management de Microsoft. Simula un centro de datosempresarial derivado del modelo de hardware, software y los sistemasde servidores del cliente.

Indy está inmerso en la versión 2.0 de la suite Microsoft SystemCenter para la que aún no hay fecha prevista de salida, ni tan siquierauna aproximación. La versión actual, la 1.0 llamada System Center 2005es la primera suite de gestión integrada para el Windows Server Systeme incluye el System Management Server 2003, Microsoft OperationsManager 2005 y el nuevo sistema común de reporting.

Se habló de él en el Summit celebrado en Las Vegas el pasado mes demarzo. La web del Summit 2004: http://www2.mms2004.com.

Más información en Microsoft Watch: http://www.microsoft-watch.comy en el sito Betanews http://www.betanews.com/article.php3?sid=1079576470

¿Qué es Lonestar?Aparte de un mítico grupo de rock catalán de los años 70, Lonestar es

el nombre en clave de la próxima versión del sistema operativo de Microsoftpara Tablet PC. Si bien se iba a vender como un add-on para los usuariosde Tablet PC, finalmente será incluido dentro de Windows XP SP2. Tendráun nuevo SDK para desarrolladores e integración con Office 2003.

¿Qué es Windows XP Reloaded?Windows XP Reloaded es el nombre en clave para la versión de

Windows XP que hará de puente entre la actual y Longhorn.

¿Qué es Symphony y Harmony?Symphony es el nombre en clave de la próxima versión de Windows

XP Media Center Edition el cual está basado en XP SP2. Una versiónprevia a Windows XP Media Center Edition 2004. Harmony es el nom-bre en clave del próximo Windows XP Media Center Edition 2004.

Incluirá soporte para High Definition Televisión, soporte para múl-tiples sintonizadores, soporte para diferentes formatos de grabación devídeo y radio.

¿Qué es qué?¿Qué es qué?

Page 8: Concurrencia en Ado.net

IMPORTES VÁLIDOS HASTA NUEVA OFERTA

DATOS DE FACTURACIÓN

CIF/NIF . . . . . . . . . . . . . . . . . . . . .Empresa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Nombre y apellidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Dirección . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Población . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Código Postal . . . . . . . . . . . . . . . . . . . Provincia . . . . . . . . . . . . . . . . . . . . . . . . .Teléfono . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Fax . . . . . . . . . . . . . . . . . . . . . . . . . . . email . . . . . . . . . . . . . . . . . . . . . . . . . . . .

DATOS DE ENVÍO (sólo si son distintos de los datos de facturación)

CIF/NIF . . . . . . . . . . . . . . . . . . . . .Empresa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Nombre y apellidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Dirección . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Población . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Código Postal . . . . . . . . . . . . . . . . . . . Provincia . . . . . . . . . . . . . . . . . . . . . . . . .Teléfono . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Fax . . . . . . . . . . . . . . . . . . . . . . . . . . . email . . . . . . . . . . . . . . . . . . . . . . . . . . . .

FORMA DE PAGO

❑ Talón nominativo a nombre NETALIA, S.L.❑ Transferencia bancaria a nombre de NETALIA, S.L. a:

La Caixa - Número de cuenta 2100 4315 48 2200014696 (Indique su nombre en la transferencia)

❑ Domiciliación Bancaria (con renovación automática, previo aviso)Indique su número de cuenta:

❑ Tarjeta de crédito❑ VISA ❑ MASTERCARD

Número de su tarjeta: Fecha de caducidad: / (imprescindible)

Firma y/o sello (imprescindible)

a de de 20

Suscripción a dotNetManía

Usted autoriza a la mecanizaciónde estos datos. El responsable ydestinatario de éstos es Netalia,S.L. Usted tiene derecho a accedera sus datos, modificarlos y cance-larlos cuando lo desee. Sus datosno serán cedidos en ninguna de lasformas posibles a terceras partes yno se utilizarán más que para elbuen funcionamiento de su sus-cripción a la revista dotNetManíay para informarle de las activida-des comerciales que realice la edi-torial Netalia, S.L. Si no desea reci-bir información comercial dedotNetManía marque la casillasiguiente ❑

❑ Nº9❑ Nº3 ❑ Nº4 ❑ Nº5

Puede enviar los datos al email [email protected], al FAX (34) 91 499 13 64 o al teléfono (34) 91 666 74 77.También puede enviarlo por correo postal a la siguiente dirección:

C/ Robledal, 13528529- Rivas VaciamadridMadrid (España)

❑ Deseo suscribirme a dotNetManía por un año (11 ejemplares) y beneficiarme de la oferta del 10% de descuento por unimporte total de 60 € para España; o por 75 € para el resto de Europa; o por 90 € para el resto del mundo (IVA incluido).

❑ Deseo suscribirme a dotNetManía por un año (11 ejemplares) por un importe de 45 € por ser estudiante (IVA incluido).Aporto fotocopia del carné de estudiante o sello del centro académico (IMPRESCINDIBLE). OFERTA VÁLIDA SÓLOPARA ESTUDIANTES RESIDENTES EN ESPAÑA.

❑ Nº6 ❑ Nº7 ❑ Nº8

Si desea algún otro número indíquelo