Monthly Archives: December 2007

NHibernate Validator ready

The port of Hibernate Validator it’s ready. You can reach it at NHibernate.Contrib trunk. For documentation you can take a look at Hibernate.Validator Documentation and for examples I think that the tests are the best example.

[Post updated 01-march-2008]

NHibernate – Bulk Manipulation with SQL Native

Some days ago Fabio Maulo were made this announce at NHibernate-Hispano Group (as usual) talking about this new feature available in NHibernate: Bulk Manipulation.

For now it’s only works with SQL Native and here is an example:

using (ISession s = sf.OpenSession()){ using(ITransaction tx = s.BeginTransaction()){ s.CreateSQLQuery("update Book set Price = Price*1.1") .ExecuteUpdate(); tx.Commit(); }

Or:

using (ISession s = sf.OpenSession()){ using(ITransaction tx = s.BeginTransaction()){ s.CreateSQLQuery("update Book set Price = Price*:increase") .SetDecimal("increase",1.1m) .ExecuteUpdate(); tx.Commit(); }

Or

using (ISession s = sf.OpenSession()){ using(ITransaction tx = s.BeginTransaction()){ s.GetNamedQuery("change-book-price") .SetDecimal("value",1.1m) .ExecuteUpdate(); tx.Commit(); }

And the named query for the last query is:

<sql-query name="change-book-price"> update Book set Price = Price*:value </sql-query>

One of the common scenarios in ORM taken it as a drawback, it is the fact that we need load al objects at memory in order to make an update to all of them, a update in mass. Now there no need to do this, you can use this feature in order to get it.

The example show a simple entity Book and has a Price property (decimal). The example show how to increase the Price in a 10 %.

Analyzers at Lucene.Net

In the last post we were watching the Lucene.Net integration with NHibernate through NHibernate Search. Now lets talking about a little more about Lucene.

Lucene can index text from many sources: PDF, HTML, Word documents, etc; and this make it so attractive for applications to solve text-search problems. When Lucene finish the document parsing from a rich media, then need to convert this stream in a plain-text token format for it can digest and thus make the context get indexed.  The previous step to the index content is the analysis, and for this are the Analyzers. Lucene provide some classes that you can use for example: WhitespaceAnalyzer, this class tokenizes the text without take into account the white spaces; StopAnalyzer delete some English StopWords from the text in order to index it, for example: the, an, a, that, this, etc.

Using NHibernate Search, we can make queries against the index that Lucene maintain, whether in Memory or on File System. This is query using NHibernate Search:

QueryParser qp = new QueryParser("Summary", new StopAnalyzer()); IQuery NHQuery = s.CreateFullTextQuery(qp.Parse("series"), typeof(Book)); IList result = NHQuery.List();

QueryParser receives as parameter an Analyzer, at this case StopAnalyzer. Using this Analyzer, you find the search terms within the search query. This has nothing to do with the Analyzer that you configure at Lucene startup, that show the way that the token go to persist at index. This analyzer realize a filter at the query string in order to find the search-keywords.

To understand a little bit more about Analyzer, a made this console application based on the Lucene In Action code examples. The idea was see what output token are produced by the distinct Analyzers. Sorry the example is in Spanish, and the custom Analyzer that I made has the Spanish Stop Words. You can checkout the example here.

NHibernate Search

One of the new features of NHibernate ported from Hibernate 3.2 is NHibernate Search. The full text engine Lucene is used by NHibernate to allow applications to execute text queries. This feature you can reach at NHibernate 1.2.1 release or at NHibernate 2.0 (at trunk).

The example of NHibernate Search with NHibernate 2.0 you can download here:

NHibernate Search Demo

In order to get the text-search at the entities you must decorate with attributes your classes like this:

using NHibernate.Search; using NHibernate.Search.Attributes; [Indexed] public class Book { private string author; private int id; private string name; private string summary; public Book() { } public Book(int id,string author, string name, string summary) { this.id = id; this.author = author; this.name = name; this.summary = summary; } [DocumentId] public virtual int Id { get { return id; } set { id = value; } } [Field(Index.Tokenized, Store = Store.Yes)] public virtual string Author { get { return author; } set { author = value; } } [Field(Index.Tokenized, Store = Store.Yes)] public virtual string Summary { get { return summary; } set { summary = value; } } [Field(Index.Tokenized, Store = Store.Yes)] public virtual string Name { get { return name; } set { name = value; } } }

You can’t configure yet this at hibernate.cfg.xml. The configuration you can do like this. There are some additional steps at the traditional configuration of NHibernate that you need take into account.

cfg = new Configuration(); cfg.SetProperty("hibernate.search.default.directory_provider", typeof(RAMDirectoryProvider).AssemblyQualifiedName); cfg.SetProperty(NHibernate.Search.Environment.AnalyzerClass, typeof(StopAnalyzer).AssemblyQualifiedName); cfg.Configure(); sf = cfg.BuildSessionFactory(); SearchFactory.Initialize(cfg, sf);

I create 3 books in order to make this demo functional:

using (IFullTextSession s = Search.CreateFullTextSession(sf.OpenSession(new SearchInterceptor()))) { using(ITransaction tx = s.BeginTransaction()){ Book b1 = new Book(1, "Eric Evans", "Domain-Driven Design: Tackling Complexity in the Heart of Software", @"This book provides a broad framework for making design decisions and a technical vocabulary for discussing domain design. It is a synthesis of widely accepted best practices along with the author's own insights and experiences." ); s.Save(b1); Book b2 = new Book(2, "Pierre Kuate", "NHibernate in Action", @"In the classic style of Manning's 'In Action' series, NHibernate in Action introduces .NET developers to the NHibernate Object/Relational Mapping tool. As NHibernate is a port of Hibernate from Java to .NET."); s.Save(b2); Book b3 = new Book(3, "John Doe", "Foo book NHibernate", "Foo series book"); s.Save(b3); s.Flush(); tx.Commit(); } }

Lets “query” this scenario. This is using the interface IQuery. The text search engine try to find the “series” at the property Summary.

using (IFullTextSession s = Search.CreateFullTextSession(sf.OpenSession(new SearchInterceptor()))) { QueryParser qp = new QueryParser("id", new StopAnalyzer()); IQuery NHQuery = s.CreateFullTextQuery(qp.Parse("Summary:series"), typeof(Book)); IList result = NHQuery.List(); Debug.Assert(result.Count == 2); }

And this is using Criteria way. The example try to find the text “NHibernate” at the properties Summary and Name (name of the book).

using (IFullTextSession s = Search.CreateFullTextSession(sf.OpenSession(new SearchInterceptor()))) { IList result = s.CreateCriteria(typeof(Book)) .Add(Search.Query("Summary:NHibernate or Name:NHibernate")) .List(); Debug.Assert(result.Count == 2); }

As you can see, in order to achieve this search you must use the Interface IFullTextSession instead of ISession or IStatelessSession.