13. La aplicación [SimuPaie] – versión 9 – Integración Spring/NHibernate
Aquí proponemos revisar la aplicación ASP.NET de tres capas de la versión 7 [pam-v7-3tier-nhibernate-multivues-multipages]. La arquitectura por capas de la aplicación era la siguiente:
![]() |
En la versión anterior, la capa [DAO] se implementó utilizando el marco NHibernate. El marco Spring se utilizó únicamente para integrar las capas entre sí. El marco Spring proporciona clases de utilidad para trabajar con el marco NHibernate. El uso de estas clases facilita la escritura del código en la capa [DAO]. La arquitectura anterior evoluciona de la siguiente manera:
![]() |
Debido a la estructura en capas utilizada, la implementación de la integración Spring/NHibernate requiere modificar únicamente la capa [DAO]. No será necesario modificar las capas [Presentación] (web/ASP.NET) y [Negocio]. Esta es la principal ventaja de las arquitecturas en capas integradas con Spring.
En las siguientes secciones, construiremos la capa [DAO] con [Spring/NHibernate] comentando el código de una solución funcional. No intentaremos abarcar todas las opciones de configuración ni todos los usos del marco [Spring/NHibernate]. Los lectores pueden adaptar la solución propuesta a sus propias necesidades utilizando la documentación de Spring.NET [http://www.springframework.net/documentation.html] (junio de 2010).
El enfoque seguido para construir las capas [DAO] y [business] es el de la versión 3 descrito en el párrafo 7. El enfoque seguido para la capa [presentation] es el de la versión 7 descrito en el párrafo 11.
13.1. La capa de acceso a datos [DAO]
![]() |
13.1.1. El proyecto de Visual Studio C# para la capa [dao]
El proyecto de Visual Studio para la capa [dao] es el siguiente:
![]() |
- en [1], el proyecto en su conjunto
- la carpeta [pam] contiene las clases del proyecto, así como la configuración de las entidades de NHibernate
- los archivos [App.config] y [Dao.xml] configuran el marco Spring/NHibernate. Tendremos que describir el contenido de estos dos archivos.
- En [2], las distintas clases del proyecto
- En la carpeta [entities], encontramos las entidades NHibernate estudiadas en el proyecto [pam-dao-nhibernate]
- En la carpeta [service], encontramos la interfaz [IPamDao] y su implementación utilizando el marco Spring/NHibernate [PamDaoSpringNHibernate]. Tendremos que escribir esta nueva implementación de la interfaz [IPamDao]
- La carpeta [tests] contiene las mismas pruebas que el proyecto [pam-dao-nhibernate]. Estas prueban la misma interfaz [IPamDao].
- En [3], las referencias del proyecto. La integración de Spring/NHibernate requiere dos nuevas DLL: [Spring.Data] y [Spring.Data.NHibernate12]. Estas DLL están disponibles en el marco Spring.Net. Se han añadido a la carpeta [lib] de las DLL [4]:
![]() |
En las referencias del proyecto [3], encontrará los siguientes archivos DLL:
- NHibernate: para el ORM de NHibernate
- MySql.Data: el controlador ADO.NET para el SGBD MySQL
- Spring.Core: para el marco Spring, que se encarga de la integración de capas
- log4net: una biblioteca de registro
- nunit.framework: una biblioteca de pruebas unitarias
- Spring.Data y Spring.Data.NHibernate12: proporcionan compatibilidad con Spring/NHibernate.
Estas referencias se han extraído de la carpeta [lib] [4]. Asegúrese de que la propiedad «Copia local» de todas estas referencias esté establecida en «Verdadero» [5]:
13.1.2. Configuración del proyecto C#
El proyecto se configura de la siguiente manera:
![]() |
- En [1], el nombre del ensamblado del proyecto es [pam-dao-spring-nhibernate]. Este nombre aparece en varios archivos de configuración del proyecto.
13.1.3. Entidades en la capa [dao]
![]() |
Las entidades (objetos) necesarias para la capa [dao] se han reunido en la carpeta [entities] [1] del proyecto. Estas entidades son las mismas que las del proyecto [pam-dao-nhibernate], con una excepción en los archivos de configuración de NHibernate. Tomemos, por ejemplo, el archivo [Employee.hbm.xml]:
- En [2], el archivo está configurado para incluirse en el ensamblado del proyecto
Su contenido es el siguiente:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
namespace="Pam.Dao.Entites" assembly="pam-dao-spring-nhibernate">
<class name="Employe" table="EMPLOYES">
<id name="Id" column="ID">
<generator class="native" />
</id>
<version name="Version" column="VERSION"/>
<property name="SS" column="SS" length="15" not-null="true" unique="true"/>
<property name="Nom" column="NOM" length="30" not-null="true"/>
<property name="Prenom" column="PRENOM" length="20" not-null="true"/>
<property name="Adresse" column="ADRESSE" length="50" not-null="true" />
<property name="Ville" column="VILLE" length="30" not-null="true"/>
<property name="CodePostal" column="CP" length="5" not-null="true"/>
<many-to-one name="Indemnites" column="INDEMNITE_ID" cascade="all" lazy="false"/>
</class>
</hibernate-mapping>
- Línea 2: El atributo assembly indica que el archivo [Employee.hbm.xml] se encuentra en el ensamblado [pam-dao-spring-nhibernate]
13.1.4. Configuración de Spring / NHibernate
Volvamos al proyecto de Visual C#:
![]() |
- En [1], los archivos [App.config] y [Dao.xml] configuran la integración de Spring / NHibernate
13.1.4.1. El archivo [ App.config]
El archivo [App.config] es el siguiente:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<!-- configuration sections -->
<configSections>
<sectionGroup name="spring">
<section name="parsers" type="Spring.Context.Support.NamespaceParsersSectionHandler, Spring.Core" />
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core" />
</sectionGroup>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
</configSections>
<!-- spring configuration -->
<spring>
<parsers>
<parser type="Spring.Data.Config.DatabaseNamespaceParser, Spring.Data" />
</parsers>
<context>
<resource uri="Dao.xml" />
</context>
</spring>
<!-- This section contains the log4net configuration settings -->
<!-- NOTE IMPORTANTE: logs are not active by default. They must be activated by program
avec l'instruction log4net.Config.XmlConfigurator.Configure();
! -->
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-5level %logger - %message%newline" />
</layout>
</appender>
<!-- Set default logging level to DEBUG -->
<root>
<level value="DEBUG" />
<appender-ref ref="ConsoleAppender" />
</root>
<!-- Set logging for Spring. Logger names in Spring correspond to the namespace -->
<logger name="Spring">
<level value="INFO" />
</logger>
<logger name="Spring.Data">
<level value="DEBUG" />
</logger>
<logger name="NHibernate">
<level value="DEBUG" />
</logger>
</log4net>
</configuration>
El archivo [App.config] anterior configura Spring (líneas 5–9, 15–22) y log4net (línea 10, líneas 28–53), pero no NHibernate. Los objetos de Spring no se configuran en [App.config], sino en el archivo [Dao.xml] (línea 20). Por lo tanto, la configuración de Spring/NHibernate, que consiste en declarar objetos específicos de Spring, se encuentra en este archivo.
13.1.4.2. El archivo [Dao.xml]
El archivo [Dao.xml], que contiene los objetos gestionados por Spring, es el siguiente:
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net"
xmlns:db="http://www.springframework.net/database">
<!-- Referenced by main application context configuration file -->
<description>
Application Spring / NHibernate
</description>
<!-- Database and NHibernate Configuration -->
<db:provider id="DbProvider"
provider="MySql.Data.MySqlClient"
connectionString="Server=localhost;Database=dbpam_nhibernate;Uid=root;Pwd=;"/>
<object id="NHibernateSessionFactory" type="Spring.Data.NHibernate.LocalSessionFactoryObject, Spring.Data.NHibernate12">
<property name="DbProvider" ref="DbProvider"/>
<property name="MappingAssemblies">
<list>
<value>pam-dao-spring-nhibernate</value>
</list>
</property>
<property name="HibernateProperties">
<dictionary>
<entry key="hibernate.dialect" value="NHibernate.Dialect.MySQLDialect"/>
<entry key="hibernate.show_sql" value="false"/>
</dictionary>
</property>
<property name="ExposeTransactionAwareSessionFactory" value="true" />
</object>
<!-- transaction manager -->
<object id="transactionManager"
type="Spring.Data.NHibernate.HibernateTransactionManager, Spring.Data.NHibernate12">
<property name="DbProvider" ref="DbProvider"/>
<property name="SessionFactory" ref="NHibernateSessionFactory"/>
</object>
<!-- Hibernate Template -->
<object id="HibernateTemplate" type="Spring.Data.NHibernate.Generic.HibernateTemplate">
<property name="SessionFactory" ref="NHibernateSessionFactory" />
<property name="TemplateFlushMode" value="Auto" />
<property name="CacheQueries" value="true" />
</object>
<!-- Data Access Objects -->
<object id="pamdao" type="Pam.Dao.Service.PamDaoSpringNHibernate, pam-dao-spring-nhibernate" init-method="init" destroy-method="destroy">
<property name="HibernateTemplate" ref="HibernateTemplate"/>
</object>
</objects>
- Las líneas 11–13 configuran la conexión a la base de datos [dbpam_nhibernate]. Incluyen:
- el proveedor ADO.NET necesario para la conexión, en este caso el proveedor del SGBD MySQL. Para ello, es necesario incluir el archivo DLL [Mysql.Data] en las referencias del proyecto.
- la cadena de conexión a la base de datos (servidor, nombre de la base de datos, propietario de la conexión y contraseña)
- Las líneas 15-29 configuran la SessionFactory de NHibernate, el objeto que se utiliza para obtener sesiones de NHibernate. Tenga en cuenta que todas las operaciones de base de datos se realizan dentro de una sesión de NHibernate. En la línea 15, podemos ver que la SessionFactory está implementada por la clase Spring.Data.NHibernate.LocalSessionFactoryObject, que se encuentra en el archivo DLL Spring.Data.NHibernate12.
- Línea 16: La propiedad DbProvider establece los parámetros de conexión a la base de datos (proveedor ADO.NET y cadena de conexión). Aquí, esta propiedad hace referencia al objeto DbProvider definido anteriormente en las líneas 11–13.
- Líneas 17-20: Especifican la lista de ensamblados que contienen archivos [*.hbm.xml] que configuran las entidades gestionadas por NHibernate. La línea 19 indica que estos archivos se encontrarán en el ensamblado del proyecto. Tenga en cuenta que este nombre se encuentra en las propiedades del proyecto C#. Tenga en cuenta también que todos los archivos [*.hbm.xml] se han configurado para incluirse en el ensamblado del proyecto.
- Líneas 22-27: Propiedades específicas de NHibernate.
- Línea 24: El dialecto SQL utilizado será MySQL
- Línea 25: El SQL generado por NHibernate no aparecerá en los registros de la consola. Establecer esta propiedad en true permite ver las sentencias SQL generadas por NHibernate. Esto puede ayudarle a comprender, por ejemplo, por qué una aplicación es lenta al acceder a la base de datos.
- Línea 28: Establecer la propiedad ExposeTransactionAwareSessionFactory en «true» hará que Spring gestione las anotaciones de gestión de transacciones que se encuentran en el código C#. Volveremos a esto cuando escribamos la clase que implementa la capa [DAO].
- Las líneas 32–36 definen el gestor de transacciones. Una vez más, este gestor es una clase de Spring procedente del archivo DLL Spring.Data.NHibernate12. Este gestor requiere los parámetros de conexión a la base de datos (línea 34), así como el SessionFactory de NHibernate (línea 35).
- Las líneas 39-43 definen las propiedades de la clase HibernateTemplate, que también es una clase de Spring. Esta clase se utilizará como clase de utilidades en la clase que implemente la capa [DAO]. Facilita las interacciones con los objetos de NHibernate. Esta clase tiene ciertas propiedades que deben inicializarse:
- línea 40: la SessionFactory de NHibernate
- línea 41: la propiedad TemplateFlushMode establece el modo de sincronización del contexto de persistencia de NHibernate con la base de datos. El modo Auto garantiza que la sincronización se produzca:
- al final de una transacción
- antes de una operación SELECT
- línea 42: las consultas HQL (Hibernate Query Language) se almacenarán en caché. Esto puede suponer una mejora en el rendimiento.
- Las líneas 46-48 definen la clase de implementación para la capa [dao]
- línea 46: la capa [dao] será implementada por la clase [PamdaoSpringNHibernate] en el DLL [pam-dao-spring-nhibernate]. Una vez instanciada la clase, se ejecutará inmediatamente el método init de la clase. Cuando se cierre el contenedor Spring, se ejecutará el método destroy de la clase.
- Línea 47: La clase [PamDaoSpringNHibernate] tendrá una propiedad HibernateTemplate que se inicializará con la propiedad HibernateTemplate de la línea 39.
13.1.5. Implementación de la capa [dao]
13.1.5.1. El esqueleto de la clase de implementación
La interfaz [IPamDao] es la misma que en el proyecto [pam-dao-nhibernate]:
using Pam.Dao.Entites;
namespace Pam.Dao.Service {
public interface IPamDao {
// list of all employee identities
Employe[] GetAllIdentitesEmployes();
// an individual employee with benefits
Employe GetEmploye(string ss);
// list of all contributions
Cotisations GetCotisations();
}
}
- Línea 1: Importamos el espacio de nombres para las entidades de la capa [dao].
- Línea 3: La capa [dao] se encuentra en el espacio de nombres [Pam.Dao.Service]. Los elementos del espacio de nombres [Pam.Dao.Entities] pueden crearse en múltiples instancias. Los elementos del espacio de nombres [Pam.Dao.Service] se crean como una única instancia (singleton). Esto es lo que justificó la elección de los nombres de los espacios de nombres.
- Línea 4: La interfaz se denomina [IPamDao]. Define tres métodos:
- Línea 6: [GetAllIdentitesEmployes] devuelve una matriz de objetos de tipo [Employe] que representa la lista de cuidadores infantiles en un formato simplificado (apellidos, nombre, número de la Seguridad Social).
- Línea 8: [GetEmploye] devuelve un objeto [Employe]: el empleado con el número de la Seguridad Social pasado como parámetro al método, junto con las prestaciones asociadas a su categoría salarial.
- Línea 10: [GetCotisations] devuelve el objeto [Cotisations], que encapsula los tipos de las distintas cotizaciones a la Seguridad Social que se deducirán del salario bruto.
El esqueleto de la clase de implementación para esta interfaz utilizando Spring/NHibernate podría ser el siguiente:
using System;
using System.Collections;
using System.Collections.Generic;
using Pam.Dao.Entites;
using Spring.Data.NHibernate.Generic.Support;
using Spring.Transaction.Interceptor;
namespace Pam.Dao.Service {
public class PamDaoSpringNHibernate : HibernateDaoSupport, IPamDao {
// private fields
private Cotisations cotisations;
private Employe[] employes;
// init
[Transaction(ReadOnly = true)]
public void init() {
...
}
// delete object
public void destroy() {
if (HibernateTemplate.SessionFactory != null) {
HibernateTemplate.SessionFactory.Close();
}
}
// list of all employee identities
public Employe[] GetAllIdentitesEmployes() {
return employes;
}
// an individual employee with benefits
[Transaction(ReadOnly = true)]
public Employe GetEmploye(string ss) {
....
}
// list of contributions
public Cotisations GetCotisations() {
return cotisations;
}
}
}
- Línea 9: La clase [PamDaoSpringNHibernate] implementa correctamente la interfaz de la capa [dao] [IPamDao]. También deriva de la clase de Spring [HibernateDaoSupport]. Esta clase tiene una propiedad [HibernateTemplate] que se inicializa mediante la configuración de Spring que se ha establecido (línea 2 más abajo):
<object id="pamdao" type="Pam.Dao.Service.PamDaoSpringNHibernate, pam-dao-spring-nhibernate" init-method="init" destroy-method="destroy">
<property name="HibernateTemplate" ref="HibernateTemplate"/>
</object>
- En la línea 1 anterior, vemos que la definición del objeto [pamdao] especifica que los métodos init y destroy de la clase [PamDaoSpringNHibernate] deben ejecutarse en momentos específicos. Estos dos métodos están efectivamente presentes en la clase, en las líneas 16 y 21.
- Líneas 15 y 34: anotaciones que garantizan que el método anotado se ejecutará dentro de una transacción. El atributo ReadOnly=true indica que la transacción es de solo lectura. El método ejecutado dentro de la transacción puede lanzar una excepción. En este caso, Spring revierte automáticamente la transacción. Esta anotación elimina la necesidad de gestionar una transacción dentro del método.
- Línea 16: Spring ejecuta el método init inmediatamente después de instanciar la clase. Veremos que su propósito es inicializar los campos privados de las líneas 11 y 12. Se ejecutará dentro de una transacción (línea 15).
- Los métodos de la interfaz [IPamDao] se implementan en las líneas 28, 35 y 40.
- Líneas 28-30: El método [GetAllIdentitesEmployes] simplemente devuelve el atributo de la línea 12, que fue inicializado por el método init.
- Líneas 40-42: El método [GetCotisations] simplemente devuelve el atributo de la línea 11, que fue inicializado por el método init.
13.1.5.2. Métodos útiles de la clase HibernateTemplate
Utilizaremos los siguientes métodos de la clase HibernateTemplate:
IList<T> Find<T>(string hql_query) | ejecuta la consulta HQL y devuelve una lista de objetos de tipo T |
IList<T> Find<T>(string hql_query, object[]) | ejecuta una consulta HQL parametrizada por ?. Los valores de estos parámetros se proporcionan mediante la matriz de objetos. |
IList<T> LoadAll<T>() | devuelve todas las entidades de tipo T |
Hay otros métodos útiles que no tendremos ocasión de utilizar, pero que permiten recuperar, guardar, actualizar y eliminar entidades:
T Load<T>(object id) | Añade la entidad de tipo T con la clave principal id a la sesión de NHibernate. |
void SaveOrUpdate(object entity) | Inserta (INSERT) o actualiza (UPDATE) el objeto entidad dependiendo de si tiene una clave principal (UPDATE) o no (INSERT). La ausencia de una clave principal se puede configurar mediante el atributo `unsaved-values` en el archivo de configuración de la entidad. Tras la operación `SaveOrUpdate`, el objeto entidad se encuentra en la sesión de NHibernate. |
void Delete(object entity) | Elimina el objeto de entidad de la sesión de NHibernate. |
13.1.5.3. Implementación del método init
El método init de la clase [PamDaoSpringNHibernate] es, por configuración, el método que se ejecuta después de que Spring instancie la clase. Su propósito es almacenar en caché localmente las identidades simplificadas de los empleados (apellido, nombre, número de la seguridad social) y las tasas de cotización. Su código podría ser el siguiente.
[Transaction(ReadOnly = true)]
public void init() {
try {
// on récupère la liste simplifiée des employés
IList<object[]> lignes = HibernateTemplate.Find<object[]>("select e.SS,e.Nom,e.Prenom from Employe e");
// on la met dans un tableau
employes = new Employe[lignes.Count];
int i = 0;
foreach (object[] ligne in lignes) {
employes[i] = new Employe() { SS = ligne[0].ToString(), Nom = ligne[1].ToString(), Prenom = ligne[2].ToString() };
i++;
}
// on met les taux de cotisations dans un objet
cotisations = (HibernateTemplate.LoadAll<Cotisations>())[0];
} catch (Exception ex) {
// on transforme l'exception
throw new PamException(string.Format("Erreur d'accès à la BD : [{0}]", ex.ToString()), 43);
}
}
- línea 5: Se ejecuta una consulta HQL. Recupera los campos SS, LastName y FirstName de todas las entidades Employee. Devuelve una lista de objetos. Si hubiéramos solicitado el registro completo de Employee utilizando «select e from Employee e», habríamos recuperado una lista de objetos de tipo Employee.
- Líneas 7–12: Esta lista de objetos se copia en una matriz de objetos de tipo Employee.
- Línea 14: Recuperamos la lista de todas las entidades de tipo Contributions. Sabemos que esta lista solo tiene un elemento. Por lo tanto, recuperamos el primer elemento de la lista para obtener las tasas de contribución.
- Las líneas 7 y 14 inicializan los dos campos privados de la clase.
13.1.5.4. Implementación del método GetEmployee
El método GetEmployee debe devolver la entidad Employee con un SSN dado. Su código podría ser el siguiente:
[Transaction(ReadOnly = true)]
public Employe GetEmploye(string ss) {
IList<Employe> employés = null;
try {
// requête
employés = HibernateTemplate.Find<Employe>("select e from Employe e where e.SS=?", new object[]{ss});
} catch (Exception ex) {
// on transforme l'exception
throw new PamException(string.Format("Erreur d'accès à la BD lors de la demande de l'employé de n° ss [{0}] : [{1}]", ss, ex.ToString()), 41);
}
// a-t-on récupéré un employé ?
if (employés.Count == 0) {
// on signale le fait
throw new PamException(string.Format("L'employé de n° ss [{0}] n'existe pas", ss), 42);
} else {
return employés[0];
}
}
- Línea 6: Recupera la lista de empleados con un número de la Seguridad Social determinado
- línea 12: normalmente, si el empleado existe, deberíamos obtener una lista con un elemento
- línea 14: si no es así, lanza una excepción
- línea 16: si ese es el caso, devuelve el primer empleado de la lista
13.1.5.5. Conclusión
Si comparamos el código de la capa [DAO] al utilizar
- el marco Spring / NHibernate
- el marco Spring / NHibernate
nos damos cuenta de que la segunda solución permitió un código más sencillo.
13.2. Pruebas de la capa [DAO]
13.2.1. El proyecto de Visual Studio
El proyecto de Visual Studio ya se ha presentado. A modo de recordatorio:
![]() |
- en [1], el proyecto en su conjunto
- en [2], las distintas clases del proyecto. La carpeta [tests] contiene una prueba de consola [Main.cs] y una prueba unitaria [NUnit.cs].
- en [3], se compila el programa [Main.cs].
![]() |
- En [4], no se genera el archivo [NUnit.cs].
- El proyecto es una aplicación de consola. La clase que se ejecuta es la especificada en [5], la clase del archivo [Main.cs].
13.2.2. El programa de prueba de consola [Main.cs]
El programa de prueba [Main.cs] se ejecuta en la siguiente arquitectura:
![]() |
Se encarga de probar los métodos de la interfaz [IPamDao]. Un ejemplo básico podría ser el siguiente:
using System;
using Pam.Dao.Entites;
using Pam.Dao.Service;
using Spring.Context.Support;
namespace Pam.Dao.Tests {
public class MainPamDaoTests {
public static void Main() {
try {
// layer instantiation [dao]
IPamDao pamDao = (IPamDao)ContextRegistry.GetContext().GetObject("pamdao");
// list of employee identities
foreach (Employe Employe in pamDao.GetAllIdentitesEmployes()) {
Console.WriteLine(Employe.ToString());
}
// an employee with benefits
Console.WriteLine("------------------------------------");
Console.WriteLine(pamDao.GetEmploye("254104940426058"));
Console.WriteLine("------------------------------------");
// list of contributions
Cotisations cotisations = pamDao.GetCotisations();
Console.WriteLine(cotisations.ToString());
} catch (Exception ex) {
// exception display
Console.WriteLine(ex.ToString());
}
//break
Console.ReadLine();
}
}
}
- Línea 11: Solicitamos a Spring una referencia a la capa [dao].
- líneas 13–15: probamos el método [GetAllEmployeeIDs] de la interfaz [IPamDao]
- Línea 18: probamos el método [GetEmployee] de la interfaz [IPamDao]
- línea 21: prueba del método [GetCotisations] de la interfaz [IPamDao]
Spring, NHibernate y log4net se configuran a través del archivo [ App.config] descrito en la sección 13.1.4.1.
Al ejecutar el código con la base de datos descrita en la sección 6.2, se obtiene la siguiente salida en la consola:
- líneas 1-2: los 2 empleados de tipo [Employee] con solo la información [SS, Apellido, Nombre]
- línea 4: el empleado de tipo [Employee] con número de la Seguridad Social [254104940426058]
- línea 5: tipos de cotización
13.2.3. Pruebas unitarias con NUnit
Ahora pasaremos a una prueba unitaria con NUnit. El proyecto de Visual Studio para la capa [dao] evolucionará de la siguiente manera:
![]() |
- en [1], el programa de prueba [NUnit.cs]
- en [2,3], el proyecto generará una DLL llamada [pam-dao-spring-nhibernate.dll]
- en [4], la referencia a la DLL del marco de trabajo de NUnit: [nunit.framework.dll]
- en [5], la clase [Main.cs] no se incluirá en la DLL [pam-dao-spring-nhibernate]
- en [6], la clase [NUnit.cs] se incluirá en la DLL [pam-dao-spring-nhibernate]
La clase de prueba de NUnit es la siguiente:
using System.Collections;
using NUnit.Framework;
using Pam.Dao.Service;
using Pam.Dao.Entites;
using Spring.Objects.Factory.Xml;
using Spring.Core.IO;
using Spring.Context.Support;
namespace Pam.Dao.Tests {
[TestFixture]
public class NunitPamDao : AssertionHelper {
// the [dao] layer to be tested
private IPamDao pamDao = null;
// manufacturer
public NunitPamDao() {
// layer instantiation [dao]
pamDao = (IPamDao)ContextRegistry.GetContext().GetObject("pamdao");
}
// init
[SetUp]
public void Init() {
}
[Test]
public void GetAllIdentitesEmployes() {
// audit no. of employees
Expect(2, EqualTo(pamDao.GetAllIdentitesEmployes().Length));
}
[Test]
public void GetCotisations() {
// checking contribution rates
Cotisations cotisations = pamDao.GetCotisations();
Expect(3.49, EqualTo(cotisations.CsgRds).Within(1E-06));
Expect(6.15, EqualTo(cotisations.Csgd).Within(1E-06));
Expect(9.39, EqualTo(cotisations.Secu).Within(1E-06));
Expect(7.88, EqualTo(cotisations.Retraite).Within(1E-06));
}
[Test]
public void GetEmployeIdemnites() {
// individual verification
Employe employe1 = pamDao.GetEmploye("254104940426058");
Employe employe2 = pamDao.GetEmploye("260124402111742");
Expect("Jouveinal", EqualTo(employe1.Nom));
Expect(2.1, EqualTo(employe1.Indemnites.BaseHeure).Within(1E-06));
Expect("Laverti", EqualTo(employe2.Nom));
Expect(1.93, EqualTo(employe2.Indemnites.BaseHeure).Within(1E-06));
}
[Test]
public void GetEmployeIdemnites2() {
// non-existent individual verification
bool erreur = false;
try {
Employe employe1 = pamDao.GetEmploye("xx");
} catch {
erreur = true;
}
Expect(erreur, True);
}
}
}
Esta clase ya se ha tratado en la sección 7.3.4.
La generación del proyecto crea el archivo DLL [pam-dao-spring-nhibernate.dll] en la carpeta [bin/Release].
![]() |
Cargamos el archivo DLL [pam-dao-spring-nhibernate.dll] utilizando la herramienta [NUnit-Gui], versión 2.4.6, y ejecutamos las pruebas:

En el ejemplo anterior, las pruebas se han realizado con éxito.
Ejercicio práctico:
Implementa las pruebas para la clase [PamDaoSpringNHibernate] en un equipo.- Utilice diferentes archivos de configuración [Dao.xml] para utilizar otros sistemas de gestión de bases de datos (Firebird, MySQL, Postgres, SQL Server).
13.2.4. Generación de la DLL de la capa [dao]
Una vez que se haya escrito y probado la clase [PamDaoNHibernate], se generará la DLL de la capa [dao] de la siguiente manera:
![]() |
- [1], los programas de prueba se excluyen del ensamblado del proyecto
- [2,3], configuración del proyecto
- [4], compilación del proyecto
- La DLL se genera en la carpeta [bin/Release] [5]. La añadimos a las DLL que ya se encuentran en la carpeta [lib] [6]:
![]() |
13.3. La capa de negocio
Repasemos la arquitectura general de la aplicación [SimuPaie]:
![]() |
Suponemos ahora que la capa [dao] está completa y se ha encapsulado en el archivo DLL [pam-dao-spring-nhibernate.dll]. Nos centraremos ahora en la capa [business]. Esta es la capa que implementa las reglas de negocio, en este caso las reglas para calcular un salario.
El proyecto de Visual Studio para la capa de negocio podría tener el siguiente aspecto:
![]() |
- En [1], todo el proyecto se configura mediante los archivos [App.config] y [Dao.xml]. El archivo [App.config] es idéntico al del proyecto de la capa [dao] [pam-dao-spring-nhibernate]. Lo mismo se aplica al archivo [Dao.xml], salvo que declara un objeto Spring adicional con el ID pammetier. La declaración de este objeto es idéntica a la del archivo [App.config] del proyecto [pam-metier-dao-nhibernate].
- En [2], la carpeta [pam] es idéntica a la de la capa [metier] del proyecto [pam-metier-dao-nhibernate]
- En [3], las referencias utilizadas por el proyecto. Obsérvese el archivo DLL [pam-dao-spring-nhibernate] de la capa [dao] comentada anteriormente.
Pregunta: Compile el proyecto [pam-metier-dao-spring-nhibernate] anterior. Se probará por separado:
-
en modo consola mediante el programa de consola [Main.cs]
-
mediante la prueba unitaria [NUnit.cs] ejecutada por el marco NUnit
El nuevo proyecto [pam-metier-dao-spring-nhibernate] se puede compilar simplemente copiando el proyecto [pam-metier-dao-nhibernate] y modificando luego los elementos que sea necesario cambiar.
Tras las pruebas, generaremos la DLL de la capa [business], a la que llamaremos [pam-metier-dao-spring-nhibernate]:
![]() |
- en [1], la prueba NUnit superada
- en [2], el archivo DLL generado por el proyecto
Añadiremos la DLL de la capa [business] a las DLL que ya se encuentran en la carpeta [lib] [3]:
![]() |
13.4. La capa [web]
Repasemos la arquitectura general de la aplicación [SimuPaie]:
![]() |
Suponemos que las capas [dao] y [business] están completas y encapsuladas en las DLL [pam-dao-spring-nhibernate, pam-business-dao-spring-nhibernate]. A continuación, describiremos la capa web.
El proyecto de Visual Web Developer para la capa [web] se obtiene en primer lugar simplemente copiando la carpeta del proyecto web [pam-v7-3tier-nhibernate-multivues-multipages]. A continuación, se renombra el proyecto como [pam-v9-3tier-spring-nhibernate-multivues-multipages]:
![]() |
El nuevo proyecto web [pam-v9-3tier-spring-nhibernate-multivues-multipages] difiere del proyecto [pam-v7-3tier-nhibernate-multivues-multipages] en los siguientes aspectos:
- En [1], la configuración se realiza mediante los archivos [Dao.xml] y [Web.config]. El archivo [Dao.xml] no existía en [pam-v7], y el archivo [Web.config] debe incluir la configuración de Spring/NHibernate, mientras que en [pam-v7] solo se configuraba NHibernate.
- En [2], las DLL para las capas [dao] y [business] son las que acabamos de compilar.
El archivo [Dao.xml] es el que se utiliza para crear la capa [business]. El archivo [Web.config] es el de [pam-v7], al que añadimos la configuración de Spring/NHibernate que se encuentra en los archivos [App.config] de las capas [dao] y [business]. El archivo [Web.config] para [pam-v9] es el siguiente:
<configuration>
<configSections>
<sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
........
</sectionGroup>
<sectionGroup name="spring">
<section name="parsers" type="Spring.Context.Support.NamespaceParsersSectionHandler, Spring.Core" />
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core" />
</sectionGroup>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
</configSections>
<!-- spring configuration -->
<spring>
<parsers>
<parser type="Spring.Data.Config.DatabaseNamespaceParser, Spring.Data" />
</parsers>
<context>
<resource uri="~/Dao.xml" />
</context>
</spring>
............. le reste est identique au fichier [Web.config] de [pam-v7]
Las líneas 7–11 y 16–23 contienen la configuración de Spring que se encontraba en los archivos [App.config] de las capas [dao] y [business] creadas anteriormente, con una diferencia: en los archivos [App.config], la línea 17 estaba escrita de la siguiente manera:
<resource uri="Dao.xml" />
Con la siguiente configuración:
![]() |
El archivo [Dao.xml] se copia en la carpeta [bin] dentro de la carpeta del proyecto web. Con la sintaxis
<resource uri="Dao.xml" />
se buscará el archivo [Dao.xml] en el directorio actual del proceso que ejecuta la aplicación web. Resulta que este directorio no es la carpeta [bin] del proyecto web que se está ejecutando. Debes escribir:
<resource uri="~/Dao.xml" />
para que el archivo [Dao.xml] se busque en la carpeta [bin] del proyecto web ejecutado.
Pregunta: Implemente esta aplicación web en un equipo.
13.5. Conclusión
Hemos pasado de la arquitectura:
![]() |
a la arquitectura:
![]() |
El objetivo era implementar la capa [DAO] aprovechando las capacidades que ofrece la integración de Spring con NHibernate.
Observamos que esto:
- afectaba a la capa [DAO]. Esta capa era más sencilla de escribir, pero requería una configuración de Spring más compleja.
- afectaba ligeramente a las capas [business] y [web]
Esto proporcionó otro ejemplo de las ventajas de las arquitecturas en capas.























