NHibernate crea proxy a través de session.Load (), pero no a través de Linq o Criteria API

StackOverflow https://stackoverflow.com/questions/1643905

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>
¿Fue útil?

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.

  1. 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 la Url , se busca el objeto, incluidas todas sus asociaciones que no admiten la carga diferida.

  2. 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

  3. 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.

  4. Al deshabilitar not-found = " ignore " y property-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 para HippoAccountSync debe tener un generador foreign.

Recursos

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top