2011-11-25 7 views
6

Estamos creando una aplicación ASP.NET MVC que utiliza NH para el acceso a datos. Usando NH Profiler veo muchas advertencias como "WARN: estrechando proxy a Domain.CaseTask - esta operación se rompe ==". Consigo estas muy a menudo cuando la ejecución de consultas para las clases que son mapeadas en una tabla por subclase, por ejemplo, utilizando el proveedor de NH LINQ:Advertencia de proxy de estrechamiento de NHibernate

Query<ICaseTask>().Where(c => c.Assignee == Of || c.Operator == Of) 

donde el CaseTask clase hereda de tareas, activa la alerta.

La información sobre la advertencia en internet es escasa y en su mayoría insinúa que esto es algo que debe ignorarse ... ¿Qué advierte exactamente esta advertencia? ¿Debería tratarse de algo que debería corregir?

Respuesta

2

Este aviso trata sobre las clases que tienen propiedades o campos que son una subclase. IE:

public class Animal 
{ 
    public int Id {get;set;} 
} 

public class Cat : Animal 
{ 
    public int Weight {get;set;} 
} 

public class Person 
{ 
    public Cat Pet {get;set;} 
} 

NHibernate se molesta cuando se carga la entidad persona, ya que no quiere echar para usted porque el comportamiento se vuelve impredecible. A menos que le digas a NHibernate cómo tratar con Equals (entre otra lógica), no sabrá cómo hacer esa comparación por sí mismo.

La idea básica para corregir esto es dejar que NHibernate coloque el objeto de la clase base en el gráfico y luego tratar con el molde (tenga en cuenta que esta configuración usaría algunas asignaciones ligeramente diferentes - he hecho esto para simplificar el código pero obviamente se puede hacer manteniendo las propiedades que getters/setters completos):

public class Animal 
    { 
     public int Id {get;set;} 
    } 

public class Cat : Animal 
{ 
    public int Weight {get;set;} 
} 

public class Person 
{ 
    private Animal _pet; 
    public Cat Pet { 
     get{return _pet as Cat;} 
    } 
} 
+0

¿Es esto un gran problema? ¿Qué pasa si ignoramos esta ADVERTENCIA? – Beatles1692

+1

Ser un gran negocio o no depende del nivel de riesgo que está dispuesto a aceptar. Como siempre habrá una desconexión entre su código y su base de datos, no siempre se puede asegurar que el casting funcionará. Esto dará lugar a errores que pueden ser difíciles de diagnosticar y que pueden no resolverse sin cambios en la base de datos o el código. – Fourth

2

La realidad es más complicada. Cuando carga la entidad usando session.Load o accede a una propiedad que está cargada de modo perezoso, NHibernate devuelve un objeto proxy. Ese objeto proxy estará hidratado (los datos se cargarán de DB) cuando acceda a cualquiera de sus propiedades por primera vez. Para lograr esto, NHibernate genera una clase de proxy que extiende la clase de entidad y anula todos los captadores y definidores de propiedades. Esto funciona perfectamente cuando no se utiliza la herencia, ya que no tendrá forma de diferenciar entre proxy y clase de entidad (clase base de proxy), p. prueba simple proxy is MyEntity siempre funcionará.

Ahora imaginemos que tenemos una entidad Persona:

class Person { 
    // lazy-loaded 
    public Animal Pet { get; set; } 
} 

y también tenemos Animal jerarquía de clases:

public abstract class Animal { ... } 
public class Cat { ... } 
public class Dog { ... } 

Supongamos ahora que Pet propiedad es cargado ligeramente, cuando se pide NHibernate para la persona pet obtendrá un objeto proxy:

var pet = somePerson.Pet; // pet will be a proxy 

Pero dado que Pet es una propiedad con carga lenta, NH no sabrá si será una instancia de Cat o Dog, por lo que hará todo lo posible y creará un proxy que se extiende a Animal. El proxy pasará la prueba para pet is Animal pero fallará las pruebas para pet is Cat o pet is Dog.

Supongamos ahora que tendrá acceso a alguna propiedad del objeto pet, lo que obligará a NH a cargar datos de DB. Ahora NH sabrá que su mascota es, por ejemplo, a Cat pero el proxy ya está generado y no se puede cambiar. Esto obligará a NHibernate a emitir una advertencia de que el proxy original para pet que se extiende tipo Animal se reducirá al tipo Cat. Esto significa que a partir de ahora el objeto proxy para animal con pet.Id que cree utilizando session.Load<Animal>(pet.Id) extenderá Cat a partir de ahora. Esto también significa que dado que Cat ahora se almacena como parte de la sesión, si cargamos una segunda persona que comparte cat con la primera, NH utilizará la instancia de proxy Cat ya disponible para poblar la propiedad de carga lenta.

Una de las consecuencias será que la referencia de objeto a pet será diferente a la referencia obtenida por session.Load<Animal>(pet.Id) (en object.ReferencesEqual sentido).

Ahora, cuando esto puede causar daño a usted:

  1. Cuando se pone sus entidades en Set s o Dictionary IES en su código o si utiliza cualquier otra estructura que requiere Equals/GetHashCode par a trabajar . Esto se puede solucionar fácilmente, proporcionando a medida Equals/GetHashCode aplicación (ver: http://www.onjava.com/pub/a/onjava/2006/09/13/dont-let-hibernate-steal-your-identity.html?page=1)

  2. Cuando intenta emitir su objeto proxy para apuntar tipo, por ejemplo, (Cat)pet, pero de nuevo no se conocen soluciones (por ejemplo Getting proxies of the correct type in NHibernate)

Así que la moraleja es evitar lo más posible la herencia en su modelo de dominio.

Cuestiones relacionadas