Sebbene apprezzo le potenzialità di NHibernate (e di conseguenza sto rivedendo la mia opinione/scetticismo sugli ORM) NON posso tirarmi indientro dal criticare alcune scelte di progettazione. Ecco una delle mie storie.
NHibernate (e anche hibernate) propone alcuni tipi built-in per aiutare a mappare colonne con comportamenti particolari; "YesNoType" (YesNo) è un esempio di questi tipi con il quale è possibile mappare booleani con colonne CHAR(1) pensate per contenere "Y" o "N". Ma in italia si dice "Si" e "No" e quindi i valori sono "S" e "N"... come fare?
La prima idea è stata quella di estendere il tipo YesNoType e ridefinirne la proprietà "TrueString" che indica il valore stringa da associare a True. Allora è proprio semplice! NO, non è possilbile: TrueString è marcato come "sealed" quindi NON ridefinibile. "TrueString" è esplicitamente marcata con sealed perchè esiste un tipo base che la definisce astratta... bene estenderò anche io il tipo base: "CharBooleanType" nato per "Maps a Boolean Property to a AnsiStringFixedLength column". Semplice anche questo! NO, non è possibile il tipo - marcato come astratto - ha un solo costruttore marcato come internal! :(
Alla fine? Alla fine - come già in altre occasioni simili - mi sono dovuto arrendere e implementare un mio IUserType che riporto qui sotto.
public class SiNoType : IUserType
{
#region IUserType Members
public object DeepCopy(object value)
{
return value;
}
public int GetHashCode(object x)
{
return x.GetHashCode();
}
public bool IsMutable
{
get { return false; }
}
public object NullSafeGet(IDataReader rs, string[] names, object owner)
{
string name = names[0];
return !rs[name].Equals("S");
}
public void NullSafeSet(IDbCommand cmd, object value, int index)
{
string db_value = (value.Equals(true)) ? "S" : "N";
IDbDataParameter parameter = (IDbDataParameter)cmd.Parameters[index];
parameter.Value = db_value;
}
public Type ReturnedType
{
get { return typeof(bool); }
}
public SqlType[] SqlTypes
{
get { return new SqlType[] { new SqlType(DbType.AnsiStringFixedLength, 1) }; }
}
bool IUserType.Equals(object x, object y)
{
return x.Equals(y);
}
#endregion
}
Non c'era altra soluzione? In realtà credo si sarebbe potuto estendere YesNoType e ridefinirne invece i metodi "NullSafeGet" e "NullSafeSet" cercando di by-passare quindi l'uso di "TrueString"... ma triggerare casi d'uso per iniettare nuovo codice e provare a saltarne altro la ritengo una soluzione poco leggibile e NON sempre efficace perchè si potrebbero trascurare/dimenticare altri casi d'uso della classe che quindi sarebbe zoppa. Ho ritenuto più semplice e LEGGIBILE implementare un tipo custom.
o0O( Sono cattivo se dico che NHibernate si sente che è figlio di un padre nato al sapore di caffè? :-p)
Technorati Tags:
Data NHibernate
posted @ venerdì 9 marzo 2007 10:57