Edición masiva en GeneXus: Cerrar las pestañas References antes de empezar
Si tu Knowledge Base contiene miles de objetos, cada Save puede convertirse en una pausa innecesaria: el IDE recalcula de inmediato la información mostrada en las pestañas References y Referenced by. Cuando estás haciendo cambios en serie (ajustes de propiedades, limpieza de variables sin uso, marcar objetos como Not Generated, importar objetos, etc.) ese refresco continuo añade segundos —o minutos— a tu tarea.
¿Qué está pasando en segundo plano?
Las pestañas de referencia se alimentan de un grafo que describe todas las dependencias entre objetos. Cada guardado desencadena:
- Análisis sintáctico del objeto modificado.
- Re-cálculo de las aristas que cambian en el grafo.
- Render del resultado en cada pestaña abierta.
En KB grandes el paso 2 puede tomar varios segundos. Repetido cientos de veces se vuelve un cuello de botella innecesario.
La práctica recomendada
1. Cierra todas las pestañas References/Referenced by antes de iniciar los cambios.
Usa el botón ×
de cada pestaña de referencias o usa la opcion "Close All But this" , que cierra todas los tabs, menos el activo.
2. Realiza toda la tanda de ediciones.
3. Guarda y confirma.
4. Cuando termines, vuelve a abrir las pestañas. El refresco se hará solo una vez, con todas las modificaciones ya consolidadas.
Ventajas inmediatas
- Menos tiempo de espera: la percepción de “lag” desaparece.
- Menor carga de CPU y disco: ideal en máquinas virtuales o KB con repositorio remoto.
- Flujo de trabajo más fluido: te concentras en los cambios y no en la interfaz.
Conclusión
El truco es simple: mantén cerradas las pestañas de referencias mientras haces
ediciones masivas. Ganarás agilidad sin perder la información; siempre podrás
consultarla cuando realmente la necesites y con un solo refresco.
Extra: SOLO PARA NERDS
Solo para los que les guste optimizar sentencias en la base de datos, en GeneXus 18 Upgrade 12, para calcular las referencias, esta usando esta consulta sobre SQL Server.WITH ObjectsInModule AS (
SELECT
mcr.ToEntityId AS ModuleId,
mcr.FromEntityTypeId AS EntityTypeId,
mcr.FromEntityId AS EntityId
FROM ModelCrossReference mcr WITH (NOLOCK)
WHERE ModelId = @ModelId
AND ToEntityTypeId = @ModuleTypeId
AND LinkType = @ParentLinkType
UNION ALL
SELECT
oim.ModuleId,
mcr.FromEntityTypeId AS EntityTypeId,
mcr.FromEntityId AS EntityId
FROM ModelCrossReference mcr WITH (NOLOCK)
INNER JOIN ObjectsInModule oim
ON oim.EntityTypeId = mcr.ToEntityTypeId
AND oim.EntityId = mcr.ToEntityId
WHERE mcr.ModelId = @ModelId
AND mcr.FromEntityTypeId <> @ModuleTypeId
AND mcr.LinkType = @ParentLinkType
AND oim.EntityTypeId <> @ModuleTypeId
),
ModulesInModule AS (
SELECT
EntityId AS ModuleId,
CONVERT(VARCHAR(MAX), '') AS ModuleName
FROM ModelEntityVersion WITH (NOLOCK)
WHERE ModelId = @ModelId
AND EntityTypeId = @ModuleTypeId
AND ModelParentEntityTypeId = 0
UNION ALL
SELECT
mev.EntityId AS ModuleId,
IIF(
mim.ModuleName = '',
mev.ModelEntityVersionName,
CONCAT(mim.ModuleName, '.', mev.ModelEntityVersionName)
) AS ModuleName
FROM ModelEntityVersion mev WITH (NOLOCK)
INNER JOIN ModulesInModule mim
ON mev.ModelParentEntityId = mim.ModuleId
WHERE mev.ModelId = @ModelId
AND mev.EntityTypeId = @ModuleTypeId
)
SELECT
mcr.EntityTypeId,
mcr.EntityId,
COALESCE(mev.
mcr.LinkType,
mcr.LinkTypeInfo,
mcr.ReferenceType,
mcr.HasReferences,
COALESCE(mim.ModuleName, '') AS ModuleName
FROM (
SELECT
mcr1.ToEntityTypeId AS EntityTypeId,
mcr1.ToEntityId AS EntityId,
mcr1.LinkType,
mcr1.LinkTypeInfo,
mcr1.ReferenceType,
CONVERT(BIT, (
SELECT TOP(1) 1
FROM ModelCrossReference mcr2 WITH (NOLOCK)
WHERE mcr2.ModelId = @ModelId
AND mcr2.FromEntityTypeId = mcr1.ToEntityTypeId
AND mcr2.FromEntityId = mcr1.ToEntityId
AND mcr2.LinkType = @ObjectLinkType
AND mcr2.ToEntityTypeId IN (
SELECT EntityTypeId
FROM EntityType
WHERE EntityTypeIsModelable = 0
OR EntityTypeNamespace <> ''
)
)) AS HasReferences
FROM ModelCrossReference mcr1 WITH (NOLOCK)
WHERE mcr1.ModelId = @ModelId
AND mcr1.FromEntityTypeId = @EntityTypeId
AND mcr1.FromEntityId = @EntityId
AND mcr1.LinkType = @ObjectLinkType
AND mcr1.ToEntityTypeId IN (
SELECT EntityTypeId
FROM EntityType
WHERE EntityTypeIsModelable = 0
OR EntityTypeNamespace <> ''
)
) AS mcr
LEFT JOIN (
SELECT EntityTypeId, EntityId, ModelEntityVersionName
FROM ModelEntityVersion WITH (NOLOCK)
WHERE ModelId = @ModelId
) AS mev
ON mev.EntityTypeId = mcr.EntityTypeId
AND mev.EntityId = mcr.EntityId
LEFT JOIN ObjectsInModule oim
ON oim.EntityTypeId = mcr.EntityTypeId
AND oim.EntityId = mcr.EntityId
LEFT JOIN ModulesInModule mim
ON oim.ModuleId = mim.ModuleId;
En la KB en la que estaba trabajando, es bastante ineficiente, pues demora hasta 18 segundos en la base, y eso lo repite tantas veces como tabs de referencias abiertos tengas, multiplicado por la cantidad de objetos que modifiques en forma batch.
Use un modelo de inteligencia artificial para optimizarlo, y paso de un costo de 158 a un costo de 5 con la siguiente sentencia equivalente.
-- 1) Lista de tipos permitidos
DECLARE @AllowedTypes TABLE (EntityTypeId INT PRIMARY KEY);
INSERT INTO @AllowedTypes
SELECT EntityTypeId
FROM EntityType
WHERE EntityTypeIsModelable = 0
OR EntityTypeNamespace <> '';
-- 2) Precalcula flags de referencias
;WITH RefFlags AS (
SELECT DISTINCT
FromEntityTypeId AS EntityTypeId,
FromEntityId,
1 AS HasReferences
FROM ModelCrossReference WITH (NOLOCK)
WHERE ModelId = @ModelId
AND LinkType = @ObjectLinkType
AND ToEntityTypeId IN (SELECT EntityTypeId FROM @AllowedTypes)
),
-- 3) CTE recursiva de módulos (sin cambios sustanciales)
ObjectsInModule AS (
SELECT mcr.ToEntityId AS ModuleId
, mcr.FromEntityTypeId AS EntityTypeId
, mcr.FromEntityId AS EntityId
FROM ModelCrossReference mcr WITH (NOLOCK)
WHERE ModelId = @ModelId
AND ToEntityTypeId = @ModuleTypeId
AND LinkType = @ParentLinkType
UNION ALL
SELECT oim.ModuleId
, mcr.FromEntityTypeId
, mcr.FromEntityId
FROM ModelCrossReference mcr WITH (NOLOCK)
JOIN ObjectsInModule oim
ON oim.EntityTypeId = mcr.ToEntityTypeId
AND oim.EntityId = mcr.ToEntityId
WHERE mcr.ModelId = @ModelId
AND mcr.FromEntityTypeId<> @ModuleTypeId
AND mcr.LinkType = @ParentLinkType
),
ModulesInModule AS (
SELECT EntityId AS ModuleId
, CAST('' AS VARCHAR(MAX)) AS ModuleName
FROM ModelEntityVersion WITH (NOLOCK)
WHERE ModelId = @ModelId
AND EntityTypeId = @ModuleTypeId
AND ModelParentEntityTypeId= 0
UNION ALL
SELECT mev.EntityId
, CASE
WHEN mim.ModuleName = '' THEN mev.ModelEntityVersionName
ELSE mim.ModuleName + '.' + mev.ModelEntityVersionName
END
FROM ModelEntityVersion mev WITH (NOLOCK)
JOIN ModulesInModule mim
ON mev.ModelParentEntityId = mim.ModuleId
WHERE mev.ModelId = @ModelId
AND mev.EntityTypeId = @ModuleTypeId
)
SELECT
mcr.ToEntityTypeId AS EntityTypeId,
mcr.ToEntityId AS EntityId,
COALESCE(mev.
mcr.LinkType,
mcr.LinkTypeInfo,
mcr.ReferenceType,
COALESCE(rf.HasReferences,0) AS HasReferences,
COALESCE(mim.ModuleName,'') AS ModuleName
FROM ModelCrossReference mcr WITH (NOLOCK)
-- 4) Aplica filtros directos y únete a AllowedTypes
JOIN @AllowedTypes at
ON mcr.ToEntityTypeId = at.EntityTypeId
AND mcr.ModelId = @ModelId
AND mcr.FromEntityTypeId = @EntityTypeId
AND mcr.FromEntityId = @EntityId
AND mcr.LinkType = @ObjectLinkType
-- 5) Enlaza el flag precomputado
LEFT JOIN RefFlags rf
ON rf.EntityTypeId = mcr.ToEntityTypeId
AND rf.FromEntityId = mcr.ToEntityId
-- 6) Trae nombre de versión si existe
LEFT JOIN ModelEntityVersion mev WITH (NOLOCK)
ON mev.ModelId = @ModelId
AND mev.EntityTypeId = mcr.ToEntityTypeId
AND mev.EntityId = mcr.ToEntityId
-- 7) Finalmente enlaza con los módulos
LEFT JOIN ObjectsInModule oim
ON oim.EntityTypeId = mcr.ToEntityTypeId
AND oim.EntityId = mcr.ToEntityId
LEFT JOIN ModulesInModule mim
ON mim.ModuleId = oim.ModuleId
OPTION (RECOMPILE);
En resumen, si quieren que GeneXus esta un poquito mas rapido, CIERREN LAS VENTANAS DE REFERENCIAS cuando no las necesiten.
Comentarios
Publicar un comentario
1) Lee el post
2) Poné tu opinión sobre el mismo.
Todos los comentarios serán leidos y la mayoría son publicados.