L'altro giorno mi è capitato di dover effettuare con Lucene delle ricerche per un intervallo di date (data inizio e data fine). Siccome le date in questione potevano essere nulle si poneva il problema di come indicizzarle perchè fossero confrontabili con i valori forniti dalla ricerca (esempio minore di e maggiore di...).
Non potendo rinunciare al valore nullo sul database ho pensato di intervenire al momento dell'indicizzazione dell'entità andando a sostituire il valore nullo con un valore di default che fosse uguale al valore minimo di DateTime per la data di inizio e al valore massimo di DateTime per la data di fine.
Avvalendomi dell'aiuto di NHibernate.Search ho realizzato un FieldBridge custom che potesse intervenire nel momento dell'indicizzazione della mia entità. Un FieldBridge non è altro che un "codec" da object a string che consente di indicizzare il contenuto di una proprietà (Object To String) e di recuperarne il valore originale dall'indice (String To Object). Ecco il codice:
using System;
using NHibernate.Search.Bridge;
using NHibernate.Search.Bridge.Builtin;
using System.Globalization;
public class AdvancedDateBridge :
ITwoWayStringBridge, IStringBridge, IParameterizedBridge
{
private string _dateTimeFormat;
private string _defaultIfIsNull;
public string ObjectToString(object obj)
{
if (obj == null)
{
return _defaultIfIsNull;
}
else
{
return Convert.ToDateTime(obj).ToString(_dateTimeFormat);
}
}
public object StringToObject(string stringValue)
{
if (stringValue.Equals(_defaultIfIsNull))
{
return null;
}
return DateTime.ParseExact(stringValue,
_dateTimeFormat, CultureInfo.CurrentCulture);
}
public void SetParameterValues(object[] parameters)
{
Object format = parameters[0];
if (format != null)
this._dateTimeFormat = (string)format;
Object defaultValue = parameters[1];
if (defaultValue != null)
this._defaultIfIsNull = (string)defaultValue;
}
}
Per utilizzare questo FieldBridge è sufficiente decorare con un attributo la proprietà di tipo DateTime che si vuole indicizzare come nell'esempio di codice seguente:
[FieldBridge(typeof(AdvancedDateBridge),
new object[]{"dd/MM/yyyy",DateTime.MinValue})]
public Nullable<DateTime> StartDate { get; set; }
[FieldBridge(typeof(AdvancedDateBridge),
new object[]{"dd/MM/yyyy",DateTime.MaxValue})]
public Nullable<DateTime> EndDate { get; set; }