Può essere utile a volte indicizzare con Lucene.Net una proprietà di un oggetto che non sia una stringa o un tipo primitivo, pensiamo ad esempio alla lista di categorie di un prodotto. Per casi come questo e laddove l'accesso ai dati viene fatto con NHibernate posso raggiungere il risultato desiderato utilizzando un FieldBridge di NHibernate.Search ed un po' di reflection:
public class PropertyBridge
: ITwoWayStringBridge, IParameterizedBridge
{
private Type _type;
private string _propertyName;
public string ObjectToString(object obj)
{
StringBuilder sb = new StringBuilder();
PropertyReflector pr = new PropertyReflector();
if (obj.GetType().IsGenericType &&
typeof(PersistentGenericBag<>).IsAssignableFrom(
obj.GetType().GetGenericTypeDefinition()))
{
IEnumerable enumerable = obj as IEnumerable;
if (enumerable != null)
{
IEnumerator enumerator = enumerable.GetEnumerator();
while (enumerator.MoveNext())
{
object current = enumerator.Current;
if(current!=null)
{
sb.Append(pr.GetValue(current,_propertyName) + " ");
}
}
return sb.ToString();
}
}
else
{
sb.Append(pr.GetValue(obj,_propertyName));
}
return sb.ToString();
}
public void SetParameterValues(object[] parameters)
{
Object classType = parameters[0];
if (classType != null)
this._type = (Type)classType;
_propertyName = parameters[1].ToString();
}
public object StringToObject(string stringValue)
{
throw new NotImplementedException();
}
}
Il FieldBridge permette a NHibernate.Search di indicizzare con Lucene il contenuto di una proprietà qualora non fosse coerente utilizzare il metodo ToString() (quasi mai per i tipi non primitivi). Analizzando il codice sopra riportato si può notare come vengano passati al FieldBridge due parametri: il tipo di oggetto ed il nome della proprietà da indicizzare (righe 38-44). Con questi due parametri ed utilizzando l'utility PropertyReflector (classe di utilità scritta da Guy Mahieu per fare "deep-reflection" di proprietà) viene recuperato il valore da salvare nell'indice di Lucene. Il FieldBridge in oggetto riesce ad indicizzare sia oggetti singoli (righe 31-34) sia collezioni verificandone il tipo ed utilizzando l'interfaccia IEnumerator (righe 11-30). Qui sotto possiamo notare l'utilizzo dell'attributo per una proprietà di tipo IList<T>.
[FieldBridge(typeof(PropertyBridge),
new object[] { typeof(Category), "CategoryID" })]
public virtual IList<Category> Categories { get; set; }
Nota: il PropertyBridge visto in questo esempio nasce da una esigenza specifica e per questo motivo non ricopre tutte le casistiche possibili.