NHibernate.Validator: Constraints en Interface

Una de las cosas que aprendí de NHibernate.Validator hoy es que puedo definir una constraint en una interface. Y como no encontré mucha información quería comentar lo que hice con un ejemplo típico de mi negocio. (Por cierto al no haber nada en google puedo estar totalmente equivocado)

En el dominio de aplicaciones contables, a menudo nos encontramos con un tipo de estructura que yo llamo “Balanceable”. Balanceable significa que el movimiento debe cerrar, equilibrar, balancear.

Por ejemplo, un asiento contable, tiene que sumar igual importe en su Haber que en su Debe. En un flujo de caja, debe entrar a una o varias cajas el mismo monto que sale de otra/s. Extendiendo este concepto más allá, un movimiento de mercaderías debe descontar la misma cantidad de un depósito que lo que suma en otros. A este punto creo que ya se entiende el dominio.

La interface IBalanceable tiene esta pinta:

public interface IBalanceable
{
    bool EstaBalanceado { get; }
}

La definición de la constraint, usando fluent, es como sigue:

public class BalanceableValidationDef : ValidationDef<IBalanceable>
{
    public BalanceableValidationDef()
    {
        Define(b => b.EstaBalanceado)
            .IsTrue()
            .WithMessage("La entidad no balancea.");
    }
}

Una clase que implementa balanceable es la siguiente:

public class AsientoContable 
        : BaseEntity, IBalanceable
{
    //...un monton de código.
    
    public virtual IList<AsientoContableLinea> 
                Lineas { get; private set; }

    public bool EstaBalanceado
    {
        get
        {
            return Lineas
                .Sum(x => x.Importe * x.Signo.ToValue()) 
                    == 0;
        }
    }
}

Y el test es algo así:

[Test]
public void CuandoAsientoNoBalancea_ViolacionDeConstraint()
{
    var asiento = new AsientoContable();
    asiento.AgregarLinea(new AsientoContableLinea
                             {
                                 Importe = 1000, 
                                Signo = Signo.Debe
                             });
    asiento.GetErrors()
        .Satisfy(c => 
    c.Any(e => e.Message.Equals("La entidad no balancea.")));
    
}

Para los que no estan acostumbrados al estilo de Satisfier (es decir SharpTestEx), el test se lee así: “de este asiento dame los errores, esa colección de errores debe SATISFACER la condición de tener ALGÚN mensaje de error cuya descripción sea igual a “La entidad no balancea”. GetErrors es un extension method que usa IEntityValidator, en algún momento posteare acerca de eso.

La conclusión de este ejemplo, es que a partir de ahora, todo lo que sea IBalanceable tendrá esa constraint que yo definí una sola vez.

Por otro lado, recordar que este es el segundo ejemplo que posteo en español, con el tag MundoReal, esto quiere decir que son ejemplos donde el dominio no es un invento de mi imaginación :D. El primero fue un caso de monedas.


blog comments powered by Disqus
  • Categories

  • Archives