Pregunta

Estoy trabajando en un problema en el que tengo varias entidades, cada una de las cuales tiene una tabla de traducciones de uno a muchos correspondientes, que especifica las versiones localizadas de los campos de la entidad. (Todo esto es un esquema heredado, estoy agregando un mapa además). Por ejemplo:

  • Evento
    • IDENTIFICACIÓN
  • Translación de eventos
    • Eventid
    • Idioma
    • Título
    • otros campos

Entonces, si iba a renderizar mi información en griego, me uniría a las dos tablas y especificaría lenguaje = 'griego' y tendría todas las cosas correctas.

Lo que estoy tratando de hacer es construir mezclas sobre la marcha que incorporen directamente los datos correctos en un solo objeto y devuelvan eso como resultado de consultas, así que como:

var someEvent = session.CreateCriteria<Event>().SetMaxResults(1).UniqueResult<IEvent>();
Console.WriteLine(someEvent.Title);

Para hacer eso, estoy tratando de configurar un interceptor nhibernato para crear mixins DynamicProxy. Excepto que no funciona, y no sé por qué. Aquí está la configuración, lo mejor que pude simplificarla.

Aquí está el evento:

class Event : IEventEntity {
   //ID and props here
   public IList Translations {get; set;}
}

IEvenEntity También tiene un Getter y Setter para la lista. También hay un EventTranslation clase, que es súper simple e implementa IEventTranslation de la manera más obvia posible.

El mapa fluido para el evento:

class EventMap : ClassMap<Event>{
  //obvious ID and properties stuff here...
  HasMany<EventTranslation>(x => x.Translations);
}

Funciona bien por sí solo: puedo consultar para eventos y navegar a sus traducciones. Estoy bastante seguro de que el mapeo es bueno.

Basé la forma de mis cosas de interceptor en una genial guía por Krzysztof Koźmic por hacer algo ligeramente relacionado. Primero, creé una superinterfaz que voy a implementar con un proxy dinámico:

public interface IEvent : IEventEntity, IEventTranslation{}

Aquí está mi Interceptor NH. Obviamente, estoy pirateando como loco:

public class EventInterceptor : NHibernate.EmptyInterceptor
{
    private readonly static ProxyGenerator gen = new ProxyGenerator();

    public override object Instantiate(string clazz, NHibernate.EntityMode entityMode, object id)
    {
           var mixin = gen.CreateClassProxy(typeof(object), new[] { typeof(IEvent) }, new DynInterceptor());
                    //would also need to set the identifier here
            return mixin;
    }
}

Donde Dyninterceptor es un interceptor que realmente hace el trabajo de entrar en la bolsa de relaciones, obtener la traducción correcta y devolver el valor correcto. Los detalles no son demasiado relevantes porque nunca se llama.

Después de atar el interceptor de NH, veo que se está ejecutando, y de hecho NH consigue el elenco para IEvent Correcto (es decir, el proxy se está creando al menos). Pero por alguna razón, atornilla totalmente hidratando la entidad:

Unhandled Exception: NHibernate.PropertyAccessException: could not set a property value by reflection setter of Event.Translations ---> System.Reflection.TargetException: Object does not match target type.
   at System.Reflection.RuntimeMethodInfo.CheckConsistency(Object target)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invoke
Attr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisib
ilityChecks)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invoke
Attr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, B
indingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture)
   at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, O
bject[] index)
   at NHibernate.Properties.BasicPropertyAccessor.BasicSetter.Set(Object target,
 Object value) in C:\thirdparty\NHibernate\src\NHibernate\Properties\BasicProper
tyAccessor.cs:line 304

Me parece que no funciona porque NH está usando Reflection para establecer la propiedad, pero, por supuesto, el tipo de destino está mal porque cambié un Ievent por el evento. ¿Hay alguna forma de evitar esto?

Además, en cuanto al enfoque básico, ¿hay una mejor manera de hacer esto en NH?

¿Fue útil?

Solución

Bien, entonces, por lo complicado que hice esa pregunta, resulta que es bastante simple, y si hubiera sabido lo suficiente, podría haber hecho la pregunta como "¿Cómo hago que un objeto implemente otra interfaz sin perder su tipo? ". La respuesta es proporcionar un objetivo, como en

Type type = Type.GetType(clazz, false);
var mixin = (Event)gen.CreateClassProxy(type, new[] { typeof(IEvent) }, new DynInterceptor());

Otros consejos

No estoy seguro, pero creo que deberías usar un filtro en combinación con un EventListener para obtener el resultado que deseas. Si establece un filtro en su tabla de idiomas y usa un EventListener para habilitar el filtro antes de los eventos que desea habilitar el filtrado, puede obtener el comportamiento deseado.

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