c# - tutorial - nhibernate visual studio 2017
Manera mínima y correcta de mapear uno a muchos con NHibernate (2)
Debería agregar la cascada all-delete-orphan
en la relación one-to-many
, si elimina al Employee
la dirección también se eliminará.
Si no necesita la referencia del Employee
cree una relación inverse=false
como esta: aquí
Soy nuevo en NHibernate y C #, así que sea amable.
Tengo las siguientes dos entidades NHibernate:
Employee
{
private long _id;
private String _name;
private String _empNumber;
private IList<Address> _addresses;
//Properties...
}
y
Address
{
private long _id;
private String _addrLine1;
private String _addrLine2;
private String _city;
private String _country;
private String _postalCode;
//Properties
}
y tienen una relación one-to-many
de Employee
a Address
(cada empleado puede tener múltiples direcciones en su registro) . Convenientemente ignorando el hecho de que más de un empleado puede residir en la misma dirección.
Entiendo esto desde la perspectiva de los objetos en la memoria (las entidades NHibernate). Lo que estoy luchando con los archivos de mapeo (y estoy tomando un ejemplo fácil aquí). Esto es lo que he propuesto hasta ahora:
// Intentionally left out XML and <hibernate-mapping>
// Mappings for class ''Employee''. -->
<class name="Employee" table="Employees">
<id name="ID">
<generator class="native">
</id>
<property name="Name" />
<property name="EmpNumber" />
<bag name="Addresses">
<key column="AddressId" />
<one-to-many class="Address" />
</bag>
</class>
y
// Intentionally left out XML and <hibernate-mapping> .
// Mappings for class ''Address''
<class name="Address" table="Addresses">
<id name="ID">
<generator class="native">
</id>
// Intentionally left out name="Employee"
// as I don''t have corresponding field in Address entity.
<many-to-one class="Employee" column="EmployeeID" cascade="all" />
<property name="AddrLine1" />
<property name="AddrLine2" />
<property name="City" />
<property name="Country" />
<property name="PostalCode" />
</class>
- ¿Es esto correcto?
- Si no, parece que lo que me falta aquí es un campo en la entidad de
Address
que es una referencia a la entidadEmployee
correspondiente. Pero si es así, entonces no puedo entender por qué es necesario: no necesito obtener unaAddress
de unEmployee
, solo al revés ...
Solo algunos consejos, resumiendo los estándares más adecuados que descubrí al trabajar con NHibernate.
1) Si hay una referencia bidireccional en persitence (columna DB) , explíquela también en código C#
bidireccional .
En otras palabras, si un niño tiene referencia a uno de los padres , el padre debe hacer referencia al niño .
public class Employee
{
...
public virtual IList<Address> { get; set; }
}
public class Address
{
...
public virtual Employee Employee { get; set; }
}
Esto representa el Dominio empresarial tal como es. La dirección pertenece al empleado y el empleado pertenece a la dirección.
Si por alguna razón realmente queremos restringir eso, deberíamos
protected
modificador, pero aun así mantener la referencia enC#
2) Use inverse="true"
. Esto podría usarse solo si mapeamos ambos lados (como se indicó anteriormente), y conducirá a más "esperados y optimizados" INSERTAR y ACTUALIZAR escrituras
Leer más aquí:
inverso = ejemplo "verdadero" y explicación por mkyong
3) Use el mapeo de búsqueda por lotes casi en cualquier parte. Eso evitará problemas de 1 + N durante la consulta. Lee mas:
algunos detalles sobre la búsqueda de lotes
4) En caso de que ese único objeto (in our case Employee)
sea root
(el otro no tiene tanto sentido sin él) - use cascada. Lee mas:
nhibernate - Crear hijo actualizando padre, o crear explícitamente?
Reglas 2,3,4 en un fragmento de mapa:
<class name="Employee" ... batch-size="25">
...
<bag name="Addresses"
lazy="true"
inverse="true"
batch-size="25"
cascade="all-delete-orphan" >
// wrong! This columns is the same as for many-to-one
//<key column="AddressId" />
// it is the one column expressing the relation
<key column="EmployeeId" />
<one-to-many class="Address" />
</bag>
<class name="Address" ... batch-size="25">
...
<many-to-one not-null="true" name="Employee" column="EmployeeID" />
3) si usamos inverse="true
, no olvide asignar ambos lados de relación (mayormente crítico durante la creación)
La razón es:
instruimos a NHibernate - el otro lado (
Address
) es responsable de la relación persistente. Pero para hacerlo correctamente, esaAddress
necesita tener referencia aEmployee
: para poder mantener su ID en su columna en la tabla de direcciones.
Así que este debería ser el código estándar para crear una nueva dirección
Employee employee = ... // load or create new
Address address = new Address
{
...
Employee = employee, // this is important
};
Employee.Addresses.Add(address);
session.SaveOrUpdate(employee); // cascade will trigger the rest
También podemos introducir algún método como AddAddress()
que ocultará esta complejidad, pero establecer ambas partes es una buena práctica.