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 StartDate { get; set; }

[FieldBridge(typeof(AdvancedDateBridge), 
             new object[]{"dd/MM/yyyy",DateTime.MaxValue})]
public Nullable EndDate { get; set; }