Domanda

Sto lavorando a un problema in cui ho un numero di entità, ognuna delle quali ha una corrispondente tabella di traduzioni da uno a molti, che specifica le versioni localizzate dei campi di Entity. (Tutto questo è uno schema legacy sto aggiungendo una mappa sopra). Per esempio:

  • Evento
    • ID
  • Event tradution
    • Eventid
    • Lingua
    • Titolo
    • Altri campi

Quindi, se avessi intenzione di rendere le mie informazioni in greco, mi unirei alle due tabelle e specificherei la lingua = "greco" e avrei tutte le cose giuste.

Quello che sto cercando di fare è creare mixin sul volo che incorporano direttamente i dati giusti in un singolo oggetto e restituiscono così come il risultato delle query, così come:

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

Per fare ciò, sto cercando di impostare un intercettore NHIBERNATE per creare mixin DynamicProxy. Solo che non funziona e non so perché. Ecco la configurazione, il meglio che potrei semplificarlo.

Ecco l'evento:

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

IEvenEntity Ha anche un getter e un setter per l'elenco. C'è anche un EventTranslation classe, che è super semplice e implementa IEventTranslation Nel modo più ovvio possibile.

La mappa fluente per l'evento:

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

Funziona bene da solo: posso interrogare per eventi e navigare verso le loro traduzioni. Sono abbastanza sicuro che la mappatura sia buona.

Ho basato la forma della mia roba di intercettore su un molto bello guida di Krzysztof Koźmic per fare qualcosa di leggermente correlato. Innanzitutto, ho creato una superinterfaccia che ho intenzione di implementare con un proxy dinamico:

public interface IEvent : IEventEntity, IEventTranslation{}

Ecco il mio intercettore NH. Ovviamente, sto hackerando come un matto:

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;
    }
}

Laddove DynInterceptor è un intercettore che effettivamente fa il lavoro di entrare nella borsa delle relazioni, ottenere la giusta traduzione e restituire il giusto valore. I dettagli non sono troppo rilevanti perché non viene mai chiamato.

Dopo aver legato l'intercettore NH, vedo che sta correndo e in effetti NH ottiene il cast IEvent giusto (cioè il proxy è almeno creato). Ma per qualche motivo, si rovina totalmente idratando l'entità:

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

Mi sembra che non funzioni perché NH sta usando la riflessione per impostare la proprietà, ma ovviamente il tipo target è sbagliato perché ho scambiato un Event per l'evento. C'è un modo per aggirare questo?

Inoltre, per quanto riguarda l'approccio di base, esiste un modo migliore per farlo in NH?

È stato utile?

Soluzione

Ok, quindi per quanto complicata ho fatto questa domanda, si rivela piuttosto semplice e se avessi saputo abbastanza, avrei potuto porre la domanda come "Come faccio a creare dinamicamente un oggetto implementare un'altra interfaccia senza perdere il suo tipo? ". La risposta è fornire un obiettivo, come in

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

Altri suggerimenti

Non ne sono sicuro, ma penso che dovresti usare un filtro in combinazione con un eventlistener per ottenere il risultato che desideri. Se si imposta un filtro sulla tabella delle lingue e usi un listener per abilitare il filtro prima degli eventi che si desidera abilitare il filtro potresti ottenere il comportamento desiderato.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top