Come indicizzare una proprietà di un tipo non primitivo in Lucene.Net con un FieldBridge di NHibernate.Search

datedomenica 25 ottobre 2009 alle 21.02  - posted by Manuel Scapolan in NHibernate | Lucene.NET

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.

Lucene.Net: indicizzare nullable date con un FieldBridge custom

datemercoledì 19 agosto 2009 alle 9.09  - posted by Manuel Scapolan in Lucene.NET

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; }

About me

manuel scapolanSono un consulente informatico. Nel 2004 terminati gli studi in Ingegneria Informatica (1° livello), ho iniziato come freelance collaborando con una ditta di consulenza informatica ed una agenzia di marketing e comunicazione nello sviluppo di applicazioni web. Attualmente divido il lavoro di sviluppatore e progettista web con attività di formazione nel settore della programmazione.
View Manuel Scapolan's profile on LinkedIn

Follow me on Follow manuelscapolan on Twitter
Member of:
innova

Calendario


<<  febbraio 2012  >>
lumamegivesado
303112345
6789101112
13141516171819
20212223242526
2728291234
567891011

Disclaimer

Eccetto dove diversamente specificato, i contenuti di questo sito sono rilasciati mediante:
creative commons
Attribuzione: Non commerciale
Condividi allo stesso modo. R.2.5

Books (a bit more about my library)

Domain Driven Design - Eric Evans Applying Domain-Driven Design and Patterns - Jimmy Nilsson Refactoring to Patterns - Joshua Kerievsky Design Patterns -  Erich Gamma, Richard Helm, Ralph Johnson, John M. Vlissides Code Complete Second Edition - Steve McConnell Patterns of Enterprise Application Architecture - Martin Fowler Agile Principles, Patterns, and Practices in C# - Robert C. Martin xUnit Test Patterns - Gerard Meszaros Refactoring - Martin Fowler CLR via C# Second Edition - Jeffrey Richter Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries - Krzysztof Cwalina, Brad Abrams Don't make me think! - Steve Krug Bulletproof Ajax - Jeremy Keith

Manuel Scapolan Copyright © 2007 - 2010 - Tutti i diritti riservati - Powered by BlogEngine.NET 1.5.0.7 - silk icons by famfamfam - Time CET