Solapas principales

Pregunta
Daniel Aguilar · Oct 20, 2020

Evitar $c(0) en globals

Buenas tardes, 

Hace ya tiempo que tengo esta duda y no sé si alguno sabrá la respuesta. Cuando realizo un insert por SQL desde una aplicación externa en los campos de tipo %String si están vacíos me graba el caracter $c(0) en el global. 

Revisando la documentación he visto que existe una propiedad para las clases que extienden de %XML.Adapter que si sobreescribes el parametro XMLIGNORENULL = 1 puedes hacer que guarde cadenas vacías en lugar de nulos.

He intentado hacer que mis clases extiendan de %XML.Adapter pero si sobreescribo la propiedad sigue haciendo lo mismo, ejemplo:

¿Existe alguna forma para que si se recibe un Insert en un campo de tipo %String con valor nulo en lugar del $c(0) lo deje vacío?

Así:

 

La clase la tengo definida asi:

Class User.MiClase Extends (%Persistent, %XML.Adaptor)

y la propiedad asi:

Property miPropiedad As %String;

Gracias!

 

00
2 0 4 51

Respuestas

la SuperClase %XML.Adaptor añadida a tu clase solo afecta a la proyección XML de lo miembros esta clase User.MiClase. Cualquier cambio que hagas en un paramero de XML Adapter, como XMLIGNORENULLS solo entra en juego cuando realizas un ObjectInstance.%XMLExport() para exportar o que usas el %XMLImport o %XMLReader para importatar miembros de esta clase User.MiClase.

El $C(0) es la representación interna de SQL "" (Cambio Vacío) en los campos de una tabla / propiedades de una clase. el SQL NULL se representa internamento como "".

Es decir, si creas una tabla con:

Create table MyTable(one VARCHAR(20), two VARCHAR(20)

Insert into MyTable(one) values ('Hola')

-> Para esta fila el campo two tendra el valor SQL NULL, por lo cual el Global de la tabla (la representación interna) sera "" para este campo.

Insert into MyTable(one,two) values ('Prueba','')

-> Para esta fila, el campo two tendra el valor SQL "" (Campo Vacío), por lo cual el global de la tabla tendra $c(0) para el campo "two" en esta fila.

Esto dicho, más importante que la representación interna de los valores SQL/Objetos en el Global, que es lo que necesitas hacer? Si tienes que acceder a los globals de tablas/Objetos creado por SQL/Objetos, siempre tendrás que procesar la representación interna, o acceder via las APIs de SQL/objetos/XML/JSON que devuelven el valor introducido correctamente.

Buenos días Pierre, 

Gracias por tu respuesta, el problema que tengo con lo $c(0) en los globals es que si hago por ejemplo esto:

(Imaginemos que en este nodo del global solo guardo por id de cliente un teléfono y para este idCliente tengo un $c(0) donde debería estar el teléfono)

Set telefono = $G(^myGlobalTelefonoCliente(idCliente))

if (telefono '=""){

    ....

}

como telefono sería igual a $c(0) entraría en la condición y no es lo que quiero.

Tengo funciones de limpieza de caracteres para evitar esto pero si se pudiese traducir los $c(0) directamente en la inserción no tendría que estar controlandolo en N sitios.

Se me ocurrió crear un trigger en la clase que compruebe los campos antes de grabar pero no me ha funcionado, ejemplo:

Trigger AntesInsert [ Event = INSERT, Time = BEFORE ]
{
    S:({telefono}=$c(0)) {telefono}=""
}

Un saludo,

Buenos días, lancé esta misma pregunta en la comunidad global y me dieron la respuesta, explico la solución:

El problema que tenía con los $c(0) es que se insertaban cuando por SQL hacía un insert en un campo de tipo %String con el valor de string vacio ""

Este es un comportamiento estandar de cache para las propiedades de tipo %String. La solución que me dieron era sobreescribir el comportamiento del metodo Normalize, para esto creé una clase que extendiese de %String y sobreescribí el metodo Normalize modificando su comportamiento para que en la devolución hiciese la traducción del $c(0) por ""

Clase Extendida de %String con el metodo Normalize sobreescrito:

Class User.StringoNoEmpty Extends %String [ Language = objectscript ] {

ClassMethod Normalize(%val As %RawString) As %String [ CodeMode = generator, ServerOnly = 1 ]

{

{
    set code="%val"
    if %parameter("TRUNCATE"),%parameter("MAXLEN")'="" { set code="$e(%val,1,"_(+%parameter("MAXLEN"))_")" }
    $$$GENERATE("    RETURN $tr("_code_",$c(0),"""")")
    RETURN $$$OK
}

}

Y luego en la clase defino la propiedad del nuevo tipo en lugar de String

Property myString As User.StringoNoEmpty;

Espero que le sirva a alguien mas de ayuda.

Un saludo

¡Qué bien que has resuelto tu duda! yes