José F. Romaniello

Las aventuras y desventuras de un codificador.

Gracias al comentario de Fabio Maulo, sobre mi anterior post fue que decidí escribir escribir este post.

Evidentemente si alguien decide enumerar el diccionario tendremos un serio problema, ya que como antes mencioné, 3650 no es chiste. Aunque es un tema de mal uso de la api debería restringirlo de alguna manera. Entonces estuve estos últimos cinco minutos pensando como solucionarlo, y me vinieron dos ideas a la cabeza.

1er Idea: Propiedad indexada en la clase moneda

En vez de publicar una propiedad del tipo IDictionary<DateTime, Cotizacion>, publicar una propiedad indexada, por lo cual mi clase Moneda pasaría a ser así:

public class Moneda
{
    public virtual int Id { get; protected set; }
    public virtual string Nombre { get; set; }
    private readonly IDictionary<DateTime, Cotizacion> _cotizaciones;
    public virtual Cotizacion this[DateTime fecha]
    {
        get
        {
            Cotizacion cotizacionBuscada;
            if (_cotizaciones.TryGetValue(fecha, out cotizacionBuscada))
                return cotizacionBuscada;
            throw new InvalidOperationException("No existe cotización para la fecha buscada.");
        }
        set
        {
            _cotizaciones[fecha] = value;
        }
    }

    public Moneda()
    {
        _cotizaciones = new Dictionary<DateTime, Cotizacion>();    
    }
}

Y cómo va a hacer NHibernate para colocar las cotizaciones en ese field PRIVADO?
Simple solo ponemos este tag en el mapeo de la collection:

access="field"

Problema solucionado, nunca más se podrán enumerar (desde afuera) la colection.

2da Idea: NotEnumerableDictionary

Esta opción se me vino a la cabeza en el caso de que quisiera mantener la misma sintaxis que antes.

Les presento mi NotEnumerableDictionary (lo lamento no encontré un nombre mejor):

public class NotEnumerableDictionary<TKey, TValue>
{
    private readonly IDictionary<TKey, TValue> _dictionary;

    public NotEnumerableDictionary(IDictionary<TKey,TValue> dictionary)
    {
        _dictionary = dictionary;
    }

    public virtual TValue this[TKey key]
    {
        get
        {
            return _dictionary[key];
        }
        set
        {
            _dictionary[key] = value;
        }
    }
}

Ahora la clase Moneda quedaría así:

public class Moneda
{
    public virtual int Id { get; protected set; }
    public virtual string Nombre { get; set; }
    private readonly IDictionary<DateTime, Cotizacion> _cotizaciones;

    public virtual NotEnumerableDictionary<DateTime,Cotizacion> Cotizaciones
    {
        get
        {
            return new NotEnumerableDictionary<DateTime, Cotizacion>(_cotizaciones);
        }
    }

    public Moneda()
    {
        _cotizaciones = new Dictionary<DateTime, Cotizacion>();    
    }
}

Y el mapeo es igual que en el primer ejemplo.

En los dos ejemplos, de ninguna forma se puede utilizar linq para consultar esa collection. La consulta de Fabio debería ejecutarse así:

moneda.Cotizaciones[DateTime.Today.AddDays(-7)]

| More

Disclaimer: En este post puedo estar muy equivocado en algunas cosas (al igual que en todo lo que escribo), por lo tanto déjame un comentario, no seas amarrete.

Voy a plantear este ejemplo, con un dominio que esta relacionado a mi trabajo:

ClassDiagram1

La empresa que paga mi alimento, realiza muchas operaciones al exterior por lo tanto se hace necesario disponer en la base de datos de su sistema, una estructura que permita almacenar cotizaciones de las diferentes monedas. La entidad Cotización es relativamente sencilla, tiene dos propiedades fundamentales que son el tipo de cambio para la Compra y el tipo de cambio para la Venta, Fecha es fundamental también, puesto que la cotización que se registra es válida para una determinada fecha (y para todas las fechas existe una cotización).

Ahora bien la entidad Moneda en principio tenía solamente la propiedad Nombre, y fue ayer que se me ocurrió bueno agregar la propiedad Cotizaciones y del tipo IDictionary cuya clave del diccionario es un DateTime (que equivale a la fecha de cotización).

Típicamente esto sería muy dañino puesto que cotizaciones puede haber al rededor de:
10 años x 365 días aprox. = 3650 cotizaciones para una determinada moneda. Y ya sea que estés usando Eager o Lazy loading, traer 3650 registros desde la base es dañino. Por lo tanto la solución típica sería no trasladar esto al modelo de objetos, a pesar de que a mi parecer sería un buen diseño orientado a objetos.

Afortunadamente estoy utilizando NHibernate como ORM, y esta herramienta tiene una opción Lazy=”Extra” (a mi criterio Extra no me dice nada, pero no se cual sería un mejor nombre). Lo que hace esta opción es solo hacer fetch del elemento que se necesita siempre tratando de evitar obtener toda la collection. Desde ya si nosotros enumeramos toda la collection, lo va a hacer.

Basta de palabras y a ver el código:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="EjemploLazyExtra"
                   namespace="EjemploLazyExtra">

    <class name="Moneda">
        <id name="Id">
            <generator class="hilo"/>
        </id>
        <map name="Cotizaciones" cascade="none" lazy="extra">
            <key column="Moneda" />
            <index column="Fecha" type="DateTime" />
            <one-to-many class="Cotizacion" />
        </map>
        <property name="Nombre"/>
    </class>
    
  <class name="Cotizacion">
        <id name="Id">
            <generator class="hilo" />
        </id>
      
    <many-to-one name="Moneda" class="Moneda"  column="Moneda"/>
    <property name="Fecha" />
    <property name="Compra" />
    <property name="Venta" />
  </class>
</hibernate-mapping>

Notar como se mapea el “map” de cotizaciones y el uso de la opción lazy=”extra”.

Prueba de concepto

Cómo pruebo yo este concepto?, puede aparecer alguna gente que diga que es fácil con NHProf. En serio? Yo no lo usaría para muchas de las cosas que la gente lo esta usando ahora y creo que si uno escribe buenos tests en muchos casos no lo necesitaría, este es mi test unitario:

[Test]
public void al_obtener_cotizacion_de_moneda_solo_debe_cargar_dos_entidades()
{
    var idMoneda = crear_datos_de_ejemplo();
    sessions.Statistics.Clear();

    using(var s = sessions.OpenSession())
    using(var tx = s.BeginTransaction())
    {
        var moneda = s.Get<Moneda>(idMoneda);
        moneda.Cotizaciones[new DateTime(2009, 4, 5)].Compra.Should().Be.EqualTo(4.04m);

        
        s.Statistics.EntityCount.Should().Be.EqualTo(2);

        tx.Commit();
    }
    
}

“Crear datos de ejemplo” es un método bastante trivial que genera 1 moneda y 100 cotizaciones sobre esa moneda, la fecha es incrementada 1 día para cada cotización, y el tipo de cambio y compra son incrementados 1 centésimo. Luego, lo que estoy haciendo es obtener una moneda, y de esa moneda obtener la cotización correspondiente a la fecha 05/04/2009, verifico que la cotización sea igual a 4.04 (m de decimal).

Lo importante de esta prueba de concepto es verificar que solamente se hayan cargado dos entidades y no 101. Para eso he utilizado las estadísticas de la session de NHibernate, existe una que se llama EntityCount que me dice “cuantas entidades hay relacionadas a esta session?”.

Como también he habilitado a NHibernate para que muestre el sql que esta ejecutando, podemos comprobar el correcto funcionamiento en la consola de nuestro test runner:

--primer consulta:

SELECT moneda0_.Id     AS Id0_0_,
       moneda0_.Nombre AS Nombre0_0_
FROM   Moneda moneda0_
WHERE  moneda0_.Id=@p0;

@p0 = 98304

--segunda consulta:
SELECT cotizacion0_.Id     AS Id1_0_    ,
       cotizacion0_.Moneda AS Moneda1_0_,
       cotizacion0_.Fecha  AS Fecha1_0_ ,
       cotizacion0_.Compra AS Compra1_0_,
       cotizacion0_.Venta  AS Venta1_0_
FROM   Cotizacion cotizacion0_
WHERE  cotizacion0_.Moneda=@p0
AND    cotizacion0_.Fecha =@p1;

@p0 = 98304, @p1 = 05/04/2009 0:00:00

Último tip:

En mi camino al aprendizaje de NHibernate me he encontrado en la situación de descargar muchos ejemplos. Y en algunos casos como este, dichos ejemplos no tenían base de datos adjunta, suelo adjuntar en mis ejemplos un test case como este:

[Test, Ignore]
public void createschema()
{
    var config = new NHibernate.Cfg.Configuration();
    config.Configure();
    var schema = new SchemaExport(config);
    schema.Execute(true, true, false);
}

Este test es ignorado completamente por el test-runner a menos que lo ejecutemos explícitamente. Al ejecutarlo, simplemente creara el schema en la base de datos que hayas configurado en el archivo hibernate.cfg.xml. Cuidado; no creará la base por si solo, solo creara el schema.

El ejemplo se puede descargar en este enlace y pueden jugar a poner lazy en true y false y ver los errores que arroja, así como también las sentencias ejecutadas contra el motor.

Saludos y como siempre digo, espero que les sea útil.

| More

This time I will talk about validation. Although there is a growing use of validation frameworks like NHV, Validation Application Block, xVal, and so on, I’ve seen a lot of people doing some weird things to display error messages in the UI.

For instance:

public static void Validate(this Controller controller, object Entity)
{
    ValidatorEngine vtor = Environment.SharedEngineProvider.GetEngine();
    InvalidValue[] errors = vtor.Validate(Entity);
    foreach (InvalidValue error in errors)
    {
        controller.ModelState.AddModelError(error.PropertyName, error.Message);
    }
}

This extension method for Asp.Net MVC takes messages from NHibernate Validator and places them in the ModelState. If you are using model-binding (which is one should really be doing with MVC), I don’t like this code because the .net framework already has something for this purpose and you don’t have to do *anything*.

The interface is IDataErrorInfo and is very ugly. But it has a great value because it works within almost any presentation technology out of the box. It works for WinForm, WPF, ASP.Net MVC and ASP.Net (non-native).

So, how to combine a validation framework with IDataErrorInfo in my classes?

First way: Very easy but coupled

Create a base entity as follows:

public class VaildatableEntity : EntityBase, IDataErrorInfo
{
    string IDataErrorInfo.this[string columnName]
    {
        get { 
            var messages = Environment.SharedEngineProvider.GetEngine()
                    .Validate(this, column)
                    .Select(iv => iv.Message)
                    .ToArray(); 
            return String.Join(Environment.NewLine, messages);
        }
    }

    string IDataErrorInfo.Error
    {
        get { 
            var messages = Environment.SharedEngineProvider.GetEngine()
                    .Validate(this)
                    .Select(iv => iv.Message)
                    .ToArray(); 

            return String.Join(Environment.NewLine, messages);
        }
    }
}

The wrong with this is that is very coupled to your validation framework, and is almost impossible to switch or test some concepts.

Second way: ServiceLocator

The second way is also easy, instead of using the validation framework directly, you write an interface like this and the implementation like this, (thanks Fabio Maulo) them you register the service in your DI container and ask that service in the ValidatableEntity through a ServiceLocator.

Third way: DynamicProxy

The third way is a little more complicated and is explained here by me. This approach is good because you don’t need anything in your domain. This is implemented in unhaddins and doesn’t depend on NHibernate Validator, this means that you can use any validation framework.

| More

Advertencia: Este artículo esta principalmente destinado para principiantes de .Net.

Hace mucho tiempo que tenía ganas de explicar acerca de las diferentes formas de hacer casting en .net puesto que me he encontrado muchas veces con malos usos de las diferentes sintaxis provistas por el framework. Si bien en este post los ejemplos estan CSharp, lo mismo se aplica para Vb.Net.

Por qué necesito castear?

La definición de MSDN es la siguiente:

Dado que los objetos son polimórficos, es posible que una variable de un tipo de clase base contenga un tipo derivado. Para tener acceso al método del tipo derivado, es necesario volver a convertir el valor al tipo derivado.

Para simplificar los ejemplos voy a utilizar el siguiente dominio:

2009-09-20_1723 
(Tomé esta imagen de algún post de Fabio Maulo)

Caso 1: 100% de seguridad de su tipo derivado

Hay algunos casos donde tenemos 100% de certeza de que el objeto en la variable es un derivado del tipo al cual queremos castear. Por lo tanto se usa una conversión explicita de la siguiente forma:

Animal someAnimal = GetAnimal();
var reptil = (Reptil) someAnimal;
Console.WriteLine(reptil.BodyTemperature);

MAL:

Animal someAnimal = GetAnimal();
var reptil = someAnimal as Reptil;
Console.WriteLine(reptil.BodyTemperature);

A continuación voy a explicar por que esta mal, y para que se utiliza el operador “as”.

Caso 2: No tengo seguridad acerca del tipo derivado

Hacer una conversión explicita como se explico en el caso 1 producirá una excepción del tipo InvalidCastException en caso de que el objeto presente en la variable no sea derivado del tipo al cual quiero castear. Por lo tanto en caso de no conocer si es un derivado de dicho tipo, utilizaremos el operador “as” la particularidad de este operador es que en caso de no serlo el resultado es null. Por lo tanto, nunca se debería utilizar este operador sin la correspondiente validación que el resultado del casteo sea nulo;

Animal someAnimal = GetAnimal();
var reptil = someAnimal as Reptil;
if(reptil != null)
    Console.WriteLine(reptil.BodyTemperature);

MAL:

Animal someAnimal = GetAnimal();
if(someAnimal is Reptil)
{
    Reptil reptil = (Reptil) someAnimal;
    Console.WriteLine(reptil.BodyTemperature);
}

El problema de este código, es que estoy realizando dos operaciones de cast la primera para verificar si la variable es del tipo Reptil, y la segunda donde realizó el cast. Por lo tanto este código es mas costoso que el anterior y esto nos lleva al caso 3.

Caso 3: Necesito solamente saber si el objeto presente en una variable es de una clase derivada de un tipo

En algunos casos es necesario saber solamente si es un derivado de un tipo especifico, es decir, no necesito realmente una conversión.

Animal someAnimal = GetAnimal();
if(someAnimal is Reptil)
{
    Console.WriteLine("Reptil!");
}

MAL:

Animal someAnimal = GetAnimal();
if((someAnimal as Reptil) != null)
{
    Console.WriteLine("Reptil!");
}


Esto fue todo, si bien he visto algunos casos peores que los que he marcado como mal, quería exponer los mas frecuentes.

Nota: Según nos comenta Eber Irigoyen desde twitter, el último ejemplo es equivalente en términos de performance.

| More

I have talked before about INotifyPropertyChanged and a simple implementation with DynamicPorxy. This time I will show you some enhancements.

This is my IInterceptor (Castle Dynamic Proxy):

using System;
using System.Collections.Generic;
using System.ComponentModel;
using Castle.Core.Interceptor;

namespace uNhAddIns.ComponentBehaviors.Castle
{
    public class PropertyChangedInterceptor : IInterceptor
    {
        private PropertyChangedEventHandler _handler;

        #region IInterceptor Members

        public void Intercept(IInvocation invocation)
        {
            string methodName = invocation.Method.Name;

            if (invocation.Method.DeclaringType.Equals(typeof (INotifyPropertyChanged)))
            {
                if (methodName == "add_PropertyChanged")
                    _handler = 
                        (PropertyChangedEventHandler) Delegate.Combine(_handler, 
                                                     (Delegate) invocation.Arguments[0]);
                if (methodName == "remove_PropertyChanged")
                     _handler = (PropertyChangedEventHandler) Delegate.Remove(_handler, 
                                                     (Delegate) invocation.Arguments[0]);

                return;
            }
            
            invocation.Proceed();

            if (methodName.StartsWith("set_"))
                NotifyPropertyChanged(methodName, invocation.Proxy);
        }

        #endregion

        protected void NotifyPropertyChanged(string methodName, object proxy)
        {
            string propertyName = methodName.Substring(4);
            var args = new PropertyChangedEventArgs(propertyName);
            OnPropertyChanged(proxy, args);
        }

        protected void OnPropertyChanged(Object sender, PropertyChangedEventArgs e)
        {
            PropertyChangedEventHandler eventHandler = _handler;
            if (eventHandler != null) eventHandler(sender, e);
        }
    }
}

Problem: don’t notify when property doesn’t change

You don’t have to notify every time, only when the property really change, otherwise event-subscribers will have to do unnecessary things. So I will add the following test to my test suite:

[Test]
public void should_not_raise_propertychanged_when_value_doesnt_change()
{
    bool eventWasRaised = false;

    var album = container.Resolve<Album>();
    album.Title = "dark side";

    ((INotifyPropertyChanged)album).PropertyChanged +=
        (sender, e) => eventWasRaised = true;;

    album.Title = "dark side";
    eventWasRaised.Should().Be.False();
}

This test is very easy to satisfy, we need to grab the old value before proceed the invocation.
This is how we treat a set_Property now:

//remove the "set_" from the method name (for isntance set_Title)
string propertyName = invocation.Method.Name.Substring(4);

//The lastvalue is the NEW val. 
//This is important when you are setting INDEXED properties.
var indexes = invocation.Arguments
              .Where((obj, index) => 
                     index < invocation.Arguments.Length - 1)
              .ToArray();

//store the current value.
var oldValue = GetCurrentValueForProperty(invocation.Proxy,
                                          propertyName, indexes);

//store the new value
var newValue = invocation.Arguments.Last();

//proceed with the set
invocation.Proceed();

//if the value has changed, notify
if (oldValue != newValue)
    OnPropertyChanged(invocation.Proxy, propertyName);

 

Problem: readonly properties

This problem is more complicated. Suppose you have the following class:

public class Person
{
        public virtual string FirstName { get; set; }
        public virtual string LastName { get; set; }
        public virtual string Address { get; set; }
        public virtual string FullName
        {
            get
            {
                return FirstName + ' ' + LastName;
            }
        }
}

Changing “FirstName” should raise a notification for FirstName property, the same with LastName and Address. But, when we should notify that FullName has changed?. The answer is simple whenever First or Last really change.

The call to a set property does not imply that the value has actually changed.

The test:

[Test]
public void can_raise_property_changed_for_readonly_property()
{
    var person = container.Resolve<Person1>();
    bool eventWasRaised = false;

    ((INotifyPropertyChanged)person).PropertyChanged +=
            (sender, e) =>
            {
                if(e.PropertyName == "FullName")
                {
                    person.FullName.Should().Be.EqualTo("Jose");
                    eventWasRaised = true;
                }
                    
            };

    person.FirstName = "Jose";
    eventWasRaised.Should().Be.True();
}

Not only we are testing that the event is raised but also that is raised after change the FirstName value.
I have updated the IInterceptor as follows:

private IDictionary<string, PropertyInfo> _readOnlyProperties;
private IDictionary<string, object> _readOnlyPropertiesValues; 

public void Intercept(IInvocation invocation)
{
    //..

    //FIRST TIME - FIRST SET we grab readonly properties with values.
    if (_readOnlyProperties == null)
        GrabReadOnlyProperties(invocation.Proxy);

    //proceed with the set
    invocation.Proceed();

    //if the value has changed, notify
    if (oldValue != newValue)
        OnPropertyChanged(invocation.Proxy, propertyName);

    NotifyReadOnlyPropertiesChanges(invocation.Proxy);
}

private void NotifyReadOnlyPropertiesChanges(object proxy)
{
    foreach (var property in _readOnlyProperties)
    {
        object oldValue = _readOnlyPropertiesValues[property.Key];
        object newValue = property.Value.GetValue(proxy, null);
        if(oldValue != newValue)
        {
            _readOnlyPropertiesValues[property.Key] = newValue;
            OnPropertyChanged(proxy, property.Key);
        }
    }
}

//this method should be called ONCE.
private void GrabReadOnlyProperties(object proxy)
{
    _readOnlyProperties = proxy.GetType().GetProperties()
                               .Where(p => p.CanWrite == false)
                               .ToDictionary(p => p.Name, p => p);

    _readOnlyPropertiesValues = _readOnlyProperties
                                .ToDictionary(p => p.Key,
                                   p => p.Value.GetValue(proxy, null));
}

Problems:

  • I’m using too much reflection and this will affect the performance.
  • There are other cases where I can not intercept a change in read only properties. For instance: Invoice.Total, depends upon Invoice.Lines.UnitPrice – Invoice.Lines.Quantity.

This work is part of the uNhAddIns.ComponentBehaviors.

| More