Domain sin Ids (pero con ConfOrm)

Preparando un ejemplo para una nueva VAN de alt.net hispano en la que, al igual que la VAN anterior, vamos a usar ConfOrm me encontré con algo curioso, ¡¿ mi objectos de dominio no tienen Ids pero mis tablas si ?!

Siempre hablamos de que los Id de los objetos (PK a nivel de tablas) no deben ser datos significativos para el usuario por varias razones que no vamos a discutir ahora. Siempre decimos que los Id son para el sistema pero hoy me encontré habiendo generado un Domain sin Id, podría decirse: “los Id son para la base de datos”.

Las clases del Domain son las siguientes:

public class Cliente
{
  private readonly IList<Extraccion> _extracciones;
 
  public Cliente()
  {
    _extracciones = new List<Extraccion>();
  }
 
  public virtual string Nombre { get; set; }
  public virtual Cuenta Cuenta { get; set; }
 
  public virtual IEnumerable<Extraccion> Extracciones
  {
    get { return _extracciones; }
  }
 
  public virtual bool RetirarPlata(int importe)
  {
    if (Cuenta != null && Cuenta.Saldo > importe)
    {
      Cuenta.Saldo -= importe;
      Extraccion extraccion = new Extraccion { Fecha = DateTime.Now, Importe = importe };
      _extracciones.Add(extraccion);
      extraccion.Cliente = this;
      return true;
    }
    return false;
  }
}
 
public class Extraccion
{
  public virtual Cliente Cliente { get; set; }
  public virtual DateTime Fecha { get; set; }
  public virtual int Importe { get; set; }
}
 
public class Cuenta
{
  public virtual int Saldo { get; set; }
  public virtual int Version { get; set; }
}

Los Mappings los generamos con ConfOrm:

ObjectRelationalMapper orm = new ObjectRelationalMapper();
 
orm.TablePerClass<Cliente>();
orm.TablePerClass<Cuenta>();
orm.TablePerClass<Extraccion>();
orm.Cascade<Cliente, Cuenta>(Cascade.All);
orm.VersionProperty<Cuenta>(c => c.Version);
 
var mapper = new Mapper(orm);
mapper.Customize<Cliente>(c => c.Property(p => p.Nombre, m => m.Unique(true)));
mapper.Customize<Cliente>(c => c.Property(p => p.Nombre, m => m.NotNullable(true)));
 
HbmMapping mapping = mapper.CompileMappingFor(typeof(Cliente).Assembly.GetTypes());
return mapping;

Si queremos escribir los mappings como xml a partir de la información generada por ConfOrm podemos, el código sería algo como:

var setting = new XmlWriterSettings { Indent = true };
var serializer = new XmlSerializer(typeof(HbmMapping));
 
var fileInfo = new FileInfo("../../mappings.hbm.xml");
 
using (TextWriter sw = new StreamWriter(fileInfo.FullName))
{
  var xw = XmlWriter.Create(sw, setting);
  serializer.Serialize(xw, mapping);
}

y el resultado:

<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" assembly="EjemploObtenerXmlDesdeConfOrm" xmlns="urn:nhibernate-mapping-2.2">
  <class name="EjemploObtenerXmlDesdeConfOrm.Domain.Cliente">
    <id type="Guid">
      <generator class="guid.comb" />
    </id>
    <property name="Nombre" unique="true" />
    <many-to-one name="Cuenta" cascade="all" />
    <bag name="Extracciones" access="field.camelcase-underscore" inverse="true" cascade="all,delete-orphan">
      <key column="Cliente" on-delete="cascade" />
      <one-to-many class="EjemploObtenerXmlDesdeConfOrm.Domain.Extraccion" />
    </bag>
  </class>
  <class name="EjemploObtenerXmlDesdeConfOrm.Domain.Extraccion">
    <id type="Guid">
      <generator class="guid.comb" />
    </id>
    <many-to-one name="Cliente" />
    <property name="Fecha" />
    <property name="Importe" />
  </class>
  <class name="EjemploObtenerXmlDesdeConfOrm.Domain.Cuenta">
    <id type="Guid">
      <generator class="guid.comb" />
    </id>
    <version name="Version" />
    <property name="Saldo" />
  </class>
</hibernate-mapping>

Recién en los mappings aparecen los Ids (pero sin tener propiedad en el objeto), quizás para muchos es algo de su día a día, pero en mi caso fue la primera vez que me doy cuenta de esto.

El DER de la base de datos, generada con SchemaExport, es:

DER

Gracias ConfOrm por seguirme enseñando sobre mappings, ORMs y OOP en general.

Con este blog-post no intento decir que es una buena práctica, seguramente que buscar nuestros objetos en la db por valores numéricos es mucho mas performante que por los datos significativos para el usuario como puede ser el nombre en este caso, pero si me hace reflexionar sobre el uso y abuso de los Ids.