Crad's .NET Blog

L'UGIblog di Marco De Sanctis
posts - 190, comments - 457, trackbacks - 70

NHibernate e lo special case

Prendo spunto da una discussione con Mario sul forum, a proposito di come sia possibile far andare d'accordo NHibernate e il pattern special case.

Uno special case è un tipo particolare che viene utilizzato in luogo di null, al fine di non rompere il polimorfismo. Non è, pertanto, una vera e propria entity, con mapping annesso, quindi se lo si prova a persistere, NHibernate ovviamente si arrabbia.

Come risolvere il problema? Un'idea può essere quella, banale, di gestire la cosa a livello di getter delle nostre property:

public Car Car
{
  get
  {
    if (car == null)
      return new MissingCar();
    else
      return car;
  }
  ....
}

Mario dice giustamente che "non gli va di condizionare una scelta di design per una limitazione di un tool". La cosa mi trova d'accordissimo, e infatti secondo me il punto di forza di NHibernate sta proprio nella sua espandibilità, che lo rende capace di adattarsi a un'infinità di situazioni eterogenee. Special case incluso! smile_teeth

Infatti, come il bravo Duz ipotizza, un'alternativa valida può essere la costruzione di un CustomAccessor. Come si può procedere? Ogni custom accessor ha il compito di restituire un Getter, utilizzato da NHibernate per leggere la proprietà persistente, e da un Setter, invocato invece ogni qual volta NHibernate, in seguito ad una lettura su DB, deve modificare il valore di una certa proprietà.

Supponendo che ogni mio special case implementi un'interfaccia ISpecialCase (senza metodi, mi serve solo come identificativo), il Getter deve banalmente verificare se la proprietà è un'istanza di ISpecialCase; in questo caso deve restituire null, così che esso sia del tutto invisibile a NHibernate.

public object Get(object target)
{
    object res = field.GetValue(target);
    if (res != null && typeof(ISpecialCase).IsAssignableFrom(res.GetType()))
        return null;
    else 
        return res;
}

Spostiamo ora la nostra attenzione sul Setter: se NHibernate tenta di assegnare il valore null alla proprietà relativa, in realtà dobbiamo assegnare un'istanza di special case. Sì, ma come facciamo a sapere che, ad esempio, lo special case di Car è il tipo MissingCar? Ho pensato di specificarlo con un CustomAttribute in testa alla dichiarazione della classe stessa. L'accessor si occupa di determinarlo, fornendolo come parametro al Setter stesso. Il codice di quest'ultimo è piuttosto banale:

public void Set(object target, object value)
{
    if (value == null && specialCase != null)
        field.SetValue(target, Activator.CreateInstance(specialCase));
    else 
        field.SetValue(target, value);
}

Semplice, no? Il progetto VS2005 con l'esempio è online a questo indirizzo, chi vuole può tirarlo giù e darci un'occhiata.

Ciaooo smile_wink

Print | posted on lunedì 20 novembre 2006 02:04 | Filed Under [ NHibernate Architettura ]

Powered by:
Powered By Subtext Powered By ASP.NET