NHibernate crea proxy a través de session.Load (), pero no a través de Linq o Criteria API
-
10-07-2019 - |
Pregunta
Tengo un problema extraño en mi proyecto actual. La carga diferida para consultas no funciona. Cuando consulto una lista, nhibernate obtiene todas las asociaciones por separado.
Extraje pequeñas partes y lo puse en una solución separada. Básicamente, lo que tengo ahora es una tabla de cuentas y una tabla de sincronización de cuentas. Ambos tienen un ID y una URL, mientras que el ID es solo un db-guid.
Mis clases son:
public class HippoAccount
{
public virtual Guid Id { get; set; }
public virtual string Url { get; set; }
public virtual HippoAccountSync Sync { get; set; }
}
public class HippoAccountSync
{
public virtual Guid Id { get; set; }
public virtual string Url { get; set; }
public virtual HippoAccount Account { get; set; }
}
Cuando ahora cargo un objeto a través de su guid:
var account = session.Load<HippoAccount>(accountId);
Console.WriteLine(NHibernateUtil.IsPropertyInitialized(account, "Sync"))
... devuelve false
y la cuenta en sí es un proxy.
Pero al cargar una lista a través del API de criterios:
var account = (HippoAccount)session
.CreateCriteria(typeof (HippoAccount))
.Add(Restrictions.Eq("Id", accountId))
.List()[0];
... la propiedad Sync
se inicializa (disparando una segunda consulta de selección), y el objeto devuelto no es un proxy.
¿Es ese comportamiento predeterminado? ¿Qué me estoy equivocando?
El mapeo es:
<class name="HippoAccount" table="AllAccounts">
<id name="Id" type="guid">
<generator class="guid"/>
</id>
<property name="Url" />
<many-to-one
class="HippoAccountSync"
name="Sync"
not-found="ignore"
property-ref="Url">
<column name="url" />
</many-to-one>
</class>
<class name="HippoAccountSync"
mutable="false"
table="Accounts">
<id name="Id" type="guid">
<generator class="guid"/>
</id>
<property name="Url">
<column name="serviceUri" />
</property>
<many-to-one class="HippoAccount"
name="Account"
property-ref="Url"
not-found="ignore">
<column name="serviceUri" />
</many-to-one>
</class>
Solución
Después de bastante más investigación, encontré las respuestas. Respuestas, porque hay muchas cosas que pueden evitar la carga diferida en NHibernate.
Consulta vs. sesión. Cargar: Al recuperar un elemento a través de
session.Load ()
obtienes un proxy. Pero tan pronto como acceda a cualquier propiedad, digamos laUrl
, se busca el objeto, incluidas todas sus asociaciones que no admiten la carga diferida.propiedad-ref: La carga diferida solo funciona sobre una identificación de objetos. Cuando una asociación de propiedades se resuelve a través de una columna diferente en la entidad de destino, NH la busca ansiosamente. No es que esto no sea posible, simplemente no está implementado: Error
not-found = " ignore " permite claves externas inválidas , es decir, si no se encuentra la entidad referenciada, NH iniciará la propiedad con nulo. NH no intercepta el acceso a la propiedad para la carga diferida, sino que asigna un proxy de objeto. Con
not-found = " ignore "
no puede decidir si la propiedad debe establecerse en nulo o un proxy para la clave foránea dada, posiblemente inválida. Esto podría resolverse interceptando el acceso a la propiedad.-
Al deshabilitar
not-found = " ignore "
yproperty-ref
, la exportación del esquema generará restricciones que impongan una referencia circular. ¡No está bien! La asignación correcta sería una relación uno a uno restringida, donde la clave paraHippoAccountSync
debe tener un generadorforeign
.
Recursos