2009-11-09 25 views
6

Tengo dos objetos de negocio asociados - A y B. la asociación es (A-> B) muchos-a-uno, con B.Id una clave externa en A (por lo que A tiene A.B_id en el DB).NHibernate - acceder al ID de un objeto asociado sin carga diferida todo el objeto

Estoy usando lazy = true y resuelto la mayoría de mis problemas, , sin embargo, en A's ToString también quiero imprimir A.B.Id, que debería tener sin más viajes a la base de datos. pero el acceso a A.B activa el proxy, y como esto no está en el contexto de una sesión abierta, arroja una excepción.

una solución fácil pero fea sería tener la propiedad A.B_id. pero eso es parte de las cosas que intentamos evitar en primer lugar. ¿alguna forma "orgánica" de hacer esto? :) gracias!


ACTUALIZACIÓN: acabo de leer sobre almacenamiento en caché y Session.Get vs. Session.Load. antes solo lo nuevo, arroja una excepción si el objeto no existe (Session.Load) y el otro devuelve un objeto nulo (Session.Get). después de leer sobre el almacenamiento en caché here, está claro que Session.Load devuelve un proxy al objeto, y solo lo recupera de forma perezosa cuando se accede a una propiedad distinta de la ID, que es muy similar a lo que necesito de las asociaciones. por ahora agregué los identificadores de objeto por separado (B_Id agregado a A para poder acceder a él como A.B_Id en lugar de usar ABId)

+0

¿Por qué quieres hacer esto? – Paco

+0

como dije, solo para la impresión de registro, etc., en A's ToString(). No necesito otros campos de B. solo la ID. –

Respuesta

3

Por la misma razón que he usado propiedades explícitas de AB-ID para todos mis muchos relaciones uno a uno. No veo esto como una solución rápida y sucia ya que proporciona una solución a este problema y también mucha flexibilidad es el área de actualización de ahorro, es decir, no necesito recuperar de la base de datos el objeto B para asignarlo a A en Para crear la asociación cuando tengo B_ID en una cadena de consulta o en otro lugar.

Mis archivos de asignación useually tener este aspecto:

<property name="CreatorID" column="CreatorID" type="Int32" not-null="true" /> 
<many-to-one name="Creator" column="CreatorID" class="SystemUser" insert="false" update="false" cascade="none" /> 

Como se puede ver una de las 2 propiedades tiene que ser leído sólo para evitar tener NHibernate el envío de 2 veces esta columna a la base de datos cuando insertos o updatas son sucediendo. Lo anterior se hace solo como de lectura (mediante el uso de los atributos insert = "false" update = "false") de varios a uno, pero puede tener como lectura solo la propiedad CreatorID si lo desea.

Al tener solo muchos a uno, no tiene una propiedad en su clase de entidad A para mantener el valor de B.ID. La única forma de obtenerlo es accediendo al objeto B que desencadenará el proxy y activará una consulta en la base de datos (si aún no está cargado en la sesión).

Me complacerá escuchar cualquier otra opción que proporcione una solución y ofrezca el mismo tipo de flexibilidad.

+0

Todavía me gustaría que esto se pueda hacer usando solo ABId - No me gustan los datos duplicados - Tenía estas propiedades y * las * eliminé ... Investigaré más el asunto, pero por ahora esto es lo que haré . ¡Gracias! –

+0

@YonatanKarni Totalmente de acuerdo. También hay un problema de rendimiento importante con esto. Agregue un número grande, n, de entidades 'proxy' a una colección de entidades (con un tipo de respaldo definido), y mata el rendimiento, ya que n selecciona, uno por proxy, se realiza de forma secuencial, ya que 'set.Add' hace su cosa. – jasper

5

Si está utilizando NHibernate 3.2 o posterior, puede utilizar el siguiente código para obtener el identificador de objeto asociado sin otra ida y vuelta a la base de datos para cargar la totalidad del objeto:

using NHibernate.Proxy; 
... 
object id = null; 
if (obj.IsProxy()) // obj is the object you want to get its identifier. 
{ 
    var proxy = obj as INHibernateProxy; 
    if (proxy != null) 
    { 
     var li = proxy.HibernateLazyInitializer; 
     if (li != null) 
      id = li.Identifier; 
    } 
} 
1

puede utilizar el método getIdentifier de Sesión de Nhibernate:

session.GetIdentifier(obj); 
Cuestiones relacionadas