Desde hace unos días que me toca lidiar
con C# para un desarrollo de escritorio y estamos comenzando con ello.
Durante el desarrollo queremos usar NHibernate con Persistence
ya que simplifica enormemente el uso de bases de datos y en otros
proyectos lo he empleado extensivamente, aunque siempre con Java.
Antes
de entrar en materia, para aquellos que no tengan experiencia previa en
NHibernate les recomiendo leer estas dos entradas (esta y esta) para conocer un poco sobre su funcionamiento.
Lo
que voy a hacer es un ejemplo muy básico, empleando una clase que
llamaremos Empleado.cs con varios atributos de tipo string. Además
mapearé la clase con un fichero empleado.hbm.xml. Como base de datos
usaré PostgreSQL sobre Windows. Podéis consultar en esta entrada del blog como instalarlo y ponerlo en marcha.
Lo
primero de todo es la creación del proyecto con Visual Studio 2012.
Para ello en File-New Project vamos a elegir Windows Form Application y
le llamaremos Ejemplo:
Buscamos
NHibernate y lo instalamos. Empleando el NuGet nos ahorramos tener que
bajarnos las librerías y agregarlas al proyecto, haciéndolo NuGet por
nosotros.
Además necesitamos el driver de PosgreSQL de igual forma que hicimos con NHibernate. Para ello instalaremos el paquete Npgsql.
Ahora
vamos a crearnos nuestra primera clase que llamaremos Entity. Para ello
vamos a crearnos una carpeta y situaremos la clase en su interior.
Nos crearemos esta clase con el fin de
que todas las clases que nos crearemos extiendan de esta y así tener
unos parámetros comunes. Estos parámetros no son más que el Id y la
Versión. El contenido de esta clase será:
namespace Ejemplo.Entities
{
public abstract class Entity<TId>
{
public virtual TId Id { get; protected set; }
protected virtual int Version { get; set; }
public override bool Equals(object obj)
{
return Equals(obj as Entity<TId>);
}
private static bool IsTransient(Entity<TId> obj)
{
return obj != null &&
Equals(obj.Id, default(TId));
}
private Type GetUnproxiedType()
{
return GetType();
}
public virtual bool Equals(Entity<TId> other)
{
if (other == null)
return false;
if (ReferenceEquals(this, other))
return true;
if (!IsTransient(this) &&
!IsTransient(other) &&
Equals(Id, other.Id))
{
var otherType = other.GetUnproxiedType();
var thisType = GetUnproxiedType();
return thisType.IsAssignableFrom(otherType) ||
otherType.IsAssignableFrom(thisType); }
return false;
}
public override int GetHashCode()
{
if (Equals(Id, default(TId)))
return base.GetHashCode();
return Id.GetHashCode();
}
}
public abstract class Entity : Entity<Guid>
{ }
}
{
public abstract class Entity<TId>
{
public virtual TId Id { get; protected set; }
protected virtual int Version { get; set; }
public override bool Equals(object obj)
{
return Equals(obj as Entity<TId>);
}
private static bool IsTransient(Entity<TId> obj)
{
return obj != null &&
Equals(obj.Id, default(TId));
}
private Type GetUnproxiedType()
{
return GetType();
}
public virtual bool Equals(Entity<TId> other)
{
if (other == null)
return false;
if (ReferenceEquals(this, other))
return true;
if (!IsTransient(this) &&
!IsTransient(other) &&
Equals(Id, other.Id))
{
var otherType = other.GetUnproxiedType();
var thisType = GetUnproxiedType();
return thisType.IsAssignableFrom(otherType) ||
otherType.IsAssignableFrom(thisType); }
return false;
}
public override int GetHashCode()
{
if (Equals(Id, default(TId)))
return base.GetHashCode();
return Id.GetHashCode();
}
}
public abstract class Entity : Entity<Guid>
{ }
}
Una
vez que hemos hecho esto ya podemos crearnos nuestra entity
Empleado.cs. A esta clase le vamos a meter cuatro atributos tipo string
muy sencilllos:
namespace Ejemplo.Entities
{
class Empleado : Entity
{
public virtual string Nombre { get; set; }
public virtual string Direccion { get; set; }
public virtual string Telefono { get; set; }
public virtual string Fax { get; set; }
}
}
Ahora
tenemos que crearnos el fichero de mapeo de estas clases. Se tiene que
llamar Empleado.hbm.xml y con el siguiente contenido:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="Ejemplo"
namespace="Ejemplo.Entities">
<class name="Empleado">
<id name="Id">
<generator class="guid.comb" />
</id>
<natural-id mutable="true">
<property name="Nombre" not-null="true" />
</natural-id>
<version name="Version" />
<property name="Direccion" />
<property name="Telefono" />
<property name="Fax" />
</class>
</hibernate-mapping>
Si
nos fijamos en el código anterior, vemos como como hemos mapeado con
una etiqueta del tipo property cada uno de los atributos de la clase.
Además nos fijaremos en como se define la clave primaria con el atributo
generator y como seleccionamos el nombre como natural-id.
Debemos de tener en cuenta que en las propiedades de este archivo se ha de cambiar el "Build Action" a Embedded Resource.
Una
vez que hemos hecho esto nos crearemos el fichero de conexión con la
base de datos. Este fichero se tiene que llamar de forma obligatoria
Hibernate.cfg.xml. Como hemos dicho, vamos a usar la conexión con
PostgreSQL por lo que su contenido debe de ser el siguiente:
<?xml version="1.0" encoding="utf-8" ?>
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2" >
<session-factory name="NHibernate.Test">
<property name="connection.driver_class"> NHibernate.Driver.NpgsqlDriver </property>
<property name="connection.connection_string">
Server=localhost; Database=database; User ID=postgres; Password=password;</property>
<property name="dialect">NHibernate.Dialect.PostgreSQL82Dialect </property>
<mapping assembly="Empleado"/>
</session-factory>
</hibernate-configuration>
Vemos
como hemos indicado en el connection_string los parámetros de conexión
con nuestra base de datos, estos deben de ser cambiados en función de
nuestra configuración. Además debemos de cambiar en las propiedades del
archivo el Copy to Output Directory de "Do not copy" a "Copy if never"
Ahora
vamos a modificar el formulario añadiendo 4 Label con 4 TextBox. En
cada uno de los EditText vamos a recoger los parámetros para la creación
de un nuevo empleado cuando se pulse un botón. Además nos crearemos
otro botón para leer los empleados que hayamos introducido. El aspecto
que tendrá nuestro formulario será el siguiente:
Dentro
de evento click de Crear Empleado tenemos que crearnos un objeto de la
clase Empleado y almacenarlo en la base de datos. Para ello usaremos el
siguiente código:
private void buttonCrearEmpleado_Click(object sender, EventArgs e)
{
Empleado empleado = new Empleado()
{
Nombre = textBoxNombre.Text.ToString(),
Direccion = textBoxDireccion.Text.ToString(),
Telefono = textBoxTelefono.Text.ToString(),
Fax = textBoxFax.Text.ToString()
};
var hibernateConfiguration = new Configuration().Configure();
var sessionFactory = hibernateConfiguration.BuildSessionFactory();
var session = sessionFactory.OpenSession();
var tx = session.BeginTransaction();
session.Save(empleado);
tx.Commit();
}
{
Empleado empleado = new Empleado()
{
Nombre = textBoxNombre.Text.ToString(),
Direccion = textBoxDireccion.Text.ToString(),
Telefono = textBoxTelefono.Text.ToString(),
Fax = textBoxFax.Text.ToString()
};
var hibernateConfiguration = new Configuration().Configure();
var sessionFactory = hibernateConfiguration.BuildSessionFactory();
var session = sessionFactory.OpenSession();
var tx = session.BeginTransaction();
session.Save(empleado);
tx.Commit();
}
Si
repasamos el código anterior vemos como una vez creado el objeto
Empleado nos creamos un sessionFactory, abrimos la conexión con
OpenSession, después BeginTransaction, hacemos un Save del objeto y ya
solamente nos queda el Commit para que los cambios se realicen en ese
mismo momento.
Una vez que ya tenemos
implementados el método para guardar en base de datos nuestros
empleados nos falta el método para leerlos. Para ello en el evento click
del botón leer tenemos que escribir lo siguiente: private void buttonLeerEmpleados_Click(object sender, EventArgs e)
{
var nhConfig = new Configuration().Configure();
var sessionFactory = nhConfig.BuildSessionFactory();
var session = sessionFactory.OpenSession();
var tx = session.BeginTransaction();
var empleados = GetEmpleados(session);
foreach (Empleado empleado in empleados)
{
Console.WriteLine(empleado.Nombre + " " + empleado.Direccion
+ " " + empleado.Telefono + " " + empleado.Fax + "\n");
}}
static IList<Empleado> GetEmpleados(ISession session)
{
var query = session.CreateCriteria<Empleado>()
.AddOrder(Order.Asc("Nombre"));
return query.List<Empleado>();
}
{
var nhConfig = new Configuration().Configure();
var sessionFactory = nhConfig.BuildSessionFactory();
var session = sessionFactory.OpenSession();
var tx = session.BeginTransaction();
var empleados = GetEmpleados(session);
foreach (Empleado empleado in empleados)
{
Console.WriteLine(empleado.Nombre + " " + empleado.Direccion
+ " " + empleado.Telefono + " " + empleado.Fax + "\n");
}}
static IList<Empleado> GetEmpleados(ISession session)
{
var query = session.CreateCriteria<Empleado>()
.AddOrder(Order.Asc("Nombre"));
return query.List<Empleado>();
}
Si
repasamos el código, vemos que es similar al anterior, tenemos que
abrir la conexión, luego BeginTransaction y llamamos al método
GetEmpleados que nos hemos implementado abajo. Este método mediante un
Criteria nos traemos todos los empleados y los devolvemos en una lista.
Esta lista la recorremos para imprimir en consola cada uno de los
empleados. Por último, debemos de añadir lo siguiente en la clase
Program.cs justo después del Main.
try
{
var hibernateConfiguration = new Configuration().Configure();
var sessionFactory = hibernateConfiguration.BuildSessionFactory();
var schemaExport = new SchemaExport(hibernateConfiguration);
schemaExport.Create(false, true);
}
catch (Exception err)
{ }
Lo que estamos haciendo con este código es la creación directamente de las tablas que necesitamos en nuestra base de datos.
Esta característica nos permite olvidarnos de nuestra base base de
datos, crearnos nuestro modelo mediante los archivos de mapeo .xml y
crear todas las tablas necesarias. Tenemos que tener en cuenta que cada
vez que se abra la aplicación se van a borrar las tablas que existían y
se crearán nuevas por lo que perderemos lo que existe. Por lo tanto
debemos de borrar estas líneas una vez que tengamos el modelo de datos
creado.
Si creamos un nuevo elemento tal y como vemos en la imagen siguiente y le hacemos click en el botón crear empleado:
Si abrimos pgAdminIII veremos como se ha creado la tabla y tenemos el registro en su interior.
Si ahora pulsamos el botón de leer empleados veremos en la consola los empleados que hemos creado, en este caso solamente uno.
Esto
sería una primera aproximación al uso de NHibernate con PostgreSQL. Iré
añadiendo más tutoriales a medida que avance. Todo lo relacionado con
este tipo de desarrollos lo puedes encontrar en la siguiente página del
blog (aquí)
Espero que os sirva y si tenéis cualquier duda o problema emplear los comentarios para preguntar.
Pongo aquí el enlace al repositorio desde donde se puede descargar el código empleado en este ejemplo https://github.com/josealopezpastor/NHibernate-Example
ResponderEliminarBuenisimo el post
ResponderEliminar