Skip to content

Instantly share code, notes, and snippets.

@alandalegend
Created March 29, 2025 19:57
Show Gist options
  • Save alandalegend/a20d2ded71d53f70100cbb3bb653bc25 to your computer and use it in GitHub Desktop.
Save alandalegend/a20d2ded71d53f70100cbb3bb653bc25 to your computer and use it in GitHub Desktop.
Identificar registros duplicados en XAF Listview Blazor DevExpress
/*
Hola, esta clase es para detectar duplicados visualmente en el listview de nuestro proyecto de Blazor en XAF / DevExpress
Ayuda a que sea para diversas propiedades, es reutilizable, centralizado, se usa el caché de la sesión para
evitar consultar la BD en cada refresh, y se tiene una funcionalidad de que se borré el caché cuando
algun coolaborador actualice algún registro
Puntos en este módulo:
🔧 1. Clase DuplicadoHelper.cs
🧬 2. Cómo usarlo en cualquier clase XPO (por ejemplo Servidor)
🎨 3. Usa Appearance para aplicar color visual
🔁 4. Limpieza automática del cache después de guardar (en Module.cs)
✅ Resultado Final
Bien... iniciemos con el código
*/
/*
🔧 1. Clase DuplicadoHelper.cs
*/
using DevExpress.Xpo;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
public static class DuplicadoHelper
{
// Cache de duplicados por propiedad y sesión
private static readonly ConditionalWeakTable<Session, Dictionary<string, HashSet<object>>> _cache =
new ConditionalWeakTable<Session, Dictionary<string, HashSet<object>>>();
/// <summary>
/// Determina si el valor de una propiedad está duplicado dentro de la entidad.
/// </summary>
public static bool EsDuplicado<T>(Session session, string nombrePropiedad, object valor) where T : DevExpress.Xpo.BaseObject
{
if (session == null || valor == null)
return false;
if (!_cache.TryGetValue(session, out var duplicadosPorPropiedad))
{
duplicadosPorPropiedad = new Dictionary<string, HashSet<object>>();
_cache.Add(session, duplicadosPorPropiedad);
}
var clave = $"{typeof(T).FullName}.{nombrePropiedad}";
if (!duplicadosPorPropiedad.TryGetValue(clave, out var duplicados))
{
var todos = new XPCollection<T>(session);
duplicados = todos
.GroupBy(x =>
{
var prop = typeof(T).GetProperty(nombrePropiedad);
return prop?.GetValue(x);
})
.Where(g => g.Count() > 1)
.Select(g => g.Key)
.ToHashSet();
duplicadosPorPropiedad[clave] = duplicados;
}
return duplicados.Contains(valor);
}
/// <summary>
/// Limpia el cache de duplicados cuando se hace commit de una transacción.
/// </summary>
public static void LimpiarCache(Session session)
{
_cache.Remove(session);
}
}
/*
🧬 2. Cómo usarlo en cualquier clase XPO (por ejemplo Servidor.cs)
*/
public class Servidor : BaseObject
{
/*..... todas tus demás propiedades*/
//Aquí validaremos la propiedad VMName
[NonPersistent]
public bool VMNameDuplicado =>
DuplicadoHelper.EsDuplicado<Servidor>(this.Session as Session, nameof(VMName), VMName);
//Aquí validaremos la propiedad IpInterna
[NonPersistent]
public bool IpDuplicada =>
DuplicadoHelper.EsDuplicado<Servidor>(this.Session as Session, nameof(IpInterna), IpInterna);
}
/*
🎨 3. Usa Appearance para aplicar color visual
*/
[Appearance("VMNameDuplicada", TargetItems = "VMName", Criteria = "VMNameDuplicado = true",
Context = "ListView", FontColor = "Red", BackColor = "#FFE5E5", Priority = 1)]
[Appearance("IpInternaDuplicada", TargetItems = "IpInterna", Criteria = "IpDuplicada = true",
Context = "ListView", FontColor = "Red", BackColor = "#FFE5E5", Priority = 1)]
/*
🔁 4. Limpieza automática del cache después de guardar (en Module.cs)
*/
public override void Setup(XafApplication application)
{
base.Setup(application);
application.ObjectSpaceCreated += (sender, e) =>
{
if (e.ObjectSpace is DevExpress.ExpressApp.Xpo.XPObjectSpace xp)
{
var session = xp.Session;
if (!session.IsObjectsLoading)
{
session.AfterCommitTransaction += (s, args) =>
{
DuplicadoHelper.LimpiarCache(session);
};
}
}
};
}
/*
✅ Resultado Final
♻️ Reutilizable Solo cambias el nombre del campo
⚡ Rápido Evalúa duplicados una sola vez por sesión
🧼 Limpieza automática Al guardar cambios
🔒 No se guarda en la BD Propiedades [NonPersistent]
🎯 Compatible Funciona perfecto con Blazor y XPO
PD: todo esto fue realizado gracias a mi amigo personal ChatGPT,
Espero les sirva tanto como a mi (y principalmente, les ahorre horas de debuggin) ✌️
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment