Belius' Blog

Il blog di Simone Belia
posts - 16, comments - 335, trackbacks - 31

NHibernate complex queries

Poco tempo fa (e tutt'ora) mi sono trovato di fronte ad un'applicazione sviluppata con NHibernate che richiedeva moltissimi filtri per fare delle ricerche molto complesse.

Cercando un pò in giro sono arrivato a leggere questo articolo di Ayende che esponeva una soluzione molto elegante e funzionale per effettuare ricerche complesse con NHibernate.....ed a pensarci bene è un buon pattern anche senza l'uso di NH.

L'articolo lo trovate qui: http://www.ayende.com/Blog/archive/2006/12/07/7055.aspx

Il concetto di base è quello di crearsi un oggetto Finder che non fa altro che incapsulare tutti i dati che devono essere cercati. Questo oggetto viene poi passato ad un metodo che altro non fa che valutare le informazioni presenti nell'oggetto per poi costruire il criteria o l'hql necessario.

Tornando al mio applicativo, ho notato che c'erano dei casi in cui la semplice impostazione di una Property non mi bastava poichè dovevo legarci anche come quell'informazione doveva essere trattata.

Per esempio una Property cognome doveva essere corredata anche dall'informazione di dove cercare, ossia se il valore doveva essere *contenuto*, oppure *iniziare per* o *finire per*. Altro esempio erano i valori range, come controllare se alcune informazioni erano comprese tra la data e la data.

Proprio per questo ho esteso la soluzione di Ayende creandomi un paio di classi chiamate SearchableField e SearchableRange.

L'implementazione delle classi è:

//SEARCHABLEFIELD
public class SearchableField<T>
    {
        
private T _search;
        private 
FinderOperator _expression FinderOperator.Equals;

        public 
FinderOperator Expression
        {
            
get return _expression}
            
set { _expression = value; }
        }

        
public T Search
        {
            
get return _search}
            
set { _search = value; }
        }

        
public SearchableField(T search, FinderOperator expression)
        {
            
this._search search;
            this
._expression expression;
        
}


    }

//SEARCHABLERANGE
public class SearchableRange<T>
    {
        
private SearchableField<T> _from;
        private 
SearchableField<T> _to;

        public 
SearchableField<T> From
        {
            
get return _from}
            
set { _from = value; }
        }

        
public SearchableField<T> To
        {
            
get return _to}
            
set { _to = value; }
        }


        
public SearchableRange(SearchableField<T> from, SearchableField<T> to)
        {
            
this._from from;
            this
._to to;
        
}
    }

Logicamente le due classi utilizzano i Generics così da poter essere riutilizzate a seconda del tipo da implementare.

Come noterete c'è anche un parametro di tipo FinderOperator che identifica quale comportamento di ricerca implementare.

public enum FinderOperator
    { 
        Equals 
0,
        NotEquals 
1,
        Contains 
2,
        GreaterThan 
3,
        LessThan 
4,
        GreaterOrEqualThan 
5,
        LessOrEqualThan 
6,
        In 
7,
        NotIn 
8
    
}

A questo punto l'unica cosa che era rimasta da fare è crearmi la mia classe Finder di cui qua riporto un abstract:

public class CustomerFinder
    {
    
        
#region Social Field

        
private SearchableField<string> _companyName = null;
        private int
? _customerId = null;
        private 
SearchableRange<int> _age = null;


        public SearchableRange<int> Age
        {
            
get return _age}
            
set { _age = value; }
        }

        public SearchableField<string> CompanyName
        {
            
get return _companyName}
            
set { _companyName = value; }
        }

        
public int? CustomerId
        {
            
get return _customerId}
            
set { _customerId = value; }
        }

        
#endregion

        #region
 Geographic Fields

        
private SearchableField<List<Country>> _localities = null;

        public 
SearchableField<List<Country>> Localities
        {
            
get return _localities}
            
set { _localities = value; }
        }

        
#endregion

        #region
 Economic Fields

        
private SearchableRange<DateTime?> _purchasedDates;
        private 
SearchableRange<decimal> _amount;

        public 
SearchableRange<DateTime?> PurchasedDates
        {
            
get return _purchasedDates}
            
set { _purchasedDates = value; }
        }

        
public SearchableRange<decimal> Amount
        {
            
get return _amount}
            
set { _amount = value; }
        }

        #endregion 

    
}

ed il suo utilizzo è stato una cosa del genere:

CustomerFinder cf = new CustomerFinder();

cf.CompanyName = new SearchableField<string>("Gates",FinderOperator.Contains);
cf.Age = new SearchableField<int>(25,FinderOperator.GreaterOrEqualThan);


CustomerPersistence persistence = new CustomerPersistence();
IList<Customer> list persistence.Find(cf);

Logicamente ci sarebbe ancora tanto da fare.....ma se qualcuno ha tempo potrebbe estendere ancora di più, no?

 

 


 

 

Print | posted on mercoledì 10 ottobre 2007 21:04 | Filed Under [ NHibernate ]

Feedback

Gravatar

# re: NHibernate complex queries

appena divento un guru di nHib, lo faccio io!! :)
12/10/2007 19:23 | marco
Gravatar

# [UPDATE] NHibernate complex queries

[UPDATE] NHibernate complex queries
16/10/2007 16:37 | Belius' Blog
Comments have been closed on this topic.

Powered by:
Powered By Subtext Powered By ASP.NET