NHibernate Burrow y NHibernate Search

English version

En este post voy a explicar cómo he conseguido hacer funcionar ambos proyectos a la vez usando los eventos de NHibernate que sustituyen a los clásicos interceptors. A través de estos eventos, permitimos que NHibernate.Search indexe los elementos marcados para tal efecto sin tener que obtener explícitamente la sesión, cosa que solamente deberemos hacer a la hora de buscar en los índices a través de la sesión de NHibernate.Burrow.
Para empezar, habría que configurar adecuadamente la aplicación (App.config):

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="NHibernate.Burrow" type="NHibernate.Burrow.Configuration.NHibernateBurrowCfgSection, NHibernate.Burrow" />
    <section name="nhs-configuration" type="NHibernate.Search.Cfg.ConfigurationSectionHandler, NHibernate.Search" />
  </configSections>
  <NHibernate.Burrow>
    <persistenceUnits>
      <add name="PersistenceUnit1"
           nh-config-file="hibernate.cfg.xml" />
    </persistenceUnits>
  </NHibernate.Burrow>
  <nhs-configuration xmlns='urn:nhs-configuration-1.0'>
    <search-factory>
      <property name='hibernate.search.default.directory_provider'>NHibernate.Search.Store.RAMDirectoryProvider, NHibernate.Search</property>
      <property name='hibernate.search.default.indexBase'>~/Index</property>
    </search-factory>
  </nhs-configuration>
</configuration>

El NHibernate.Search no maneja demasiado bien el tema de la sección y busca una llamada nhs-configuration, así que es mejor no cambiarle el nombre. Por otro lado, habrá que crear un fichero hibernate.cfg.xml con la configuración de NHibernate. Por ejemplo, para testado se puede usar una base de datos en memoria de SQLite:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
  <session-factory>
    <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
    <property name="dialect">NHibernate.Dialect.SQLiteDialect</property>
    <property name="connection.driver_class">NHibernate.Driver.SQLite20Driver</property>
    <property name="connection.connection_string">Data Source=:memory:;Version=3;New=True;</property>
    <property name="connection.release_mode">on_close</property>-->

    <mapping assembly="Mapped.Assembly" />
    <mapping assembly="Mapped.Assembly2" />
  </session-factory>
</hibernate-configuration>

Sin olvidar las secciones de mapping-assembly donde se indicaran los ensamblados a mapear.
Después, lo más interesante es la inicialización de Burrow para que tenga en cuenta los eventos de Search. Por ejemplo esto es lo que tengo al inicio de cada caso de test:

            var framework = new BurrowFramework();

            Configuration config = framework.BurrowEnvironment.GetNHConfig("PersistenceUnit1");

            // Poner los EventListeners
            config.SetListener(ListenerType.PostDelete, new FullTextIndexEventListener());
            config.SetListener(ListenerType.PostInsert, new FullTextIndexEventListener());
            config.SetListener(ListenerType.PostUpdate, new FullTextIndexEventListener());

            framework.BurrowEnvironment.RebuildSessionFactories();

La última línea es importante porque actualiza la sesión de NHibernate con los cambios realizados. Esto en realidad también se podría haber puesto en el fichero nhibernate.cfg.xml poniendo dentro de la sección session-factory lo siguiente:

        <listener class="NHibernate.Search.Event.FullTextIndexEventListener, NHibernate.Search" type="post-update" />
        <listener class="NHibernate.Search.Event.FullTextIndexEventListener, NHibernate.Search" type="post-insert" />
        <listener class="NHibernate.Search.Event.FullTextIndexEventListener, NHibernate.Search" type="post-delete" />

Con eso no haría falta añadir manualmente los manejadores ni regenerar los session factories.
En resumen, de este modo las entidades indexables (ver el post de Dario Quintana al respecto de NHibernate.Search) son tratadas automáticamente por la librería sin tener que hacer nada especial.
Ahora solamente quedaría hacer búsquedas sobre los índices. Por ejemplo en este caso este simple test crea una sesión de NHibernate.Search y hace una búsqueda sobre una entidad indexada, basándome en el ejemplo de Darío:

        [Test]
        public void SearchIndexedUser()
        {
            var session = Search.CreateFullTextSession(new BurrowFramework().GetSession());

            var qp = new QueryParser("UserName", new StopAnalyzer());
            var nhQuery = session.CreateFullTextQuery(qp.Parse("test"), typeof(User));

            var results = nhQuery.List();

            Assert.AreEqual(1, results.Count);
        }

Hay que tener en cuenta una cosa importante: Nhibernate.Search tiene en cuenta las transacciones y NHibernate.Burrow hace uso intensivo de las mismas, así que si en el test se crean los datos que luego se quieren buscar en el índice habrá que hacer lo siguiente:

            new BurrowFramework().CloseWorkSpace();
            new BurrowFramework().InitWorkSpace();

Con este código terminamos todas las transacciones pendientes por acometer de Burrow y se crea una nueva de modo que todos los cambios pendientes en los índices se persisten.
Y eso es todo. Con esto se pueden integrar de forma sencilla estos dos interesantes y útiles proyectos que de otro modo sería complicado ya que no se puede modificar directamente la sesión de Burrow además de ser incómodo el uso de interceptors ya que hay que trabajar un poco para poder usar varios a la vez, por lo que el mecanismo de eventos es mucho más limpio.
Finalmente comentar que ambas cosas las he hecho compilando el código del trunk tanto de NHibernate.Burrow como de NHibernate.Search que se puede conseguir en el SVN de nhcontrib contra la versión actual estable de NHibernate, la 2.0.1GA.
Espero vuestros comentarios.

Si te ha gustado esta entrada, por favor deja un comentario o suscríbete al RSS para que puedas recibir todas las novedades en tu lector de feeds favorito.
This entry was posted in Programación and tagged , , , . Bookmark the permalink.

2 Responses to "NHibernate Burrow y NHibernate Search"

Leave a reply