viernes, 12 de junio de 2009

When duplicate y campos con índice unique

Si en GeneXus (9.0) se tiene una tabla con un índice unique y se hace un for each que actualiza el campo del índice, al especificar da un warning que dice:
spc0070: No When duplicate code found to handle possible duplicate condition when updating [Atributo]
La documentación del comando for each en el Wiki, dice lo siguiente con respecto al when duplicate:
When duplicate: This clause only makes sense in procedures (because it has to do with updates); it is analyzed below. This clause will be executed if, within the body of the For Each (code1), you try to update an attribute that is a candidate key (it has a unique index) and a record with that value already exists. GeneXus uses the unique index to ensure the uniqueness of that candidate key and in case it finds duplicates, if this clause is programmed in the For Each command, it will execute its code: code2. If the clause is not included, and you try to update an attribute that is a candidate key and a record with that value already exists, no code will be executed.
El problema con esto, es que en un mismo for each puedo estar actualizando más de un campo que tenga índice unique, con lo cual no se cual es el campo donde dio el error.

El código para manejar este error, entonces debería primero hacer otro for each filtrando por cada uno de los campos con índice unique para ver cual es el que falló, y luego hacer nuevamente el update de todos los demás campos. La lógica puede quedar bastante complicada...

Una alternativa a esto que se me ocurre, es que el when duplicate pueda tener una lista de atributos que componen un índice unique, y que cuando se trata de grabar una tupla y da clave duplicada, vaya al when duplicate que corresponda.

Es más, GeneXus podría ser más inteligente, y que cada when duplicate sea un manejador de errores, que se llame para cambiar los valores de los atributos involucrados en ese when duplicate antes de hacer el update...

Capaz que la idea no quedó muy clara, voy a poner un ejemplo...

Tengo una tabla con campos:
(A*
 B
 C
 D)
que tiene índices unique por {B} y {C,D}.

Podría tener el siguiente comando for each:
for each
    where A = &A

    B = &B
    C = &C
    D = &D
when duplicate B
    B += 1
when duplicate C, D
    C = &D
    D = &C
endfor
¿Qué haría este código? Intenta hacer el update con valores [&B, &C, &D]. Si no puede porque B está repetido, entonces va al when duplicate B, calcula el nuevo valor de B, e intenta hacer el update con [&B+1, &C, &D]. Así hasta que no falle más por B... Si además falla porque los campos C, D están repetidos, entonces va al when duplicate C, D, e intenta hacer el update con [&B, &D, &C].

Hoy no hay una forma medianamente elegante de hacer esto. Porque en el when duplicate primero tengo que identificar que campo fue el que dio el error, y después volver a hacer el nuevo update con los nuevos valores, por lo que quedaría una especie de actualización recursiva.

No hay comentarios.:

Publicar un comentario