Смешивание в данных с боковым столом с nhibernate Interceptors и DynamicProxy
-
27-10-2019 - |
Вопрос
Я работаю над проблемой, в которой у меня есть ряд сущностей, каждая из которых имеет соответствующую таблицу переводов с одним ко многим, в которой указываются локализованные версии полей сущности. (Все это - устаревшая схема, которую я добавляю карту на вершину). Например:
- Мероприятие
- Я БЫ
- EventTranslation
- Eventid
- Язык
- Заголовок
- Другие поля
Итак, если бы я собирался представить свою информацию на греческом языке, я бы присоединился к двум таблицам и указал Language = «греческий» и имел все правильные вещи.
То, что я пытаюсь сделать, это создать микшины на лету, которые напрямую включают правильные данные в один объект и возвращают это в результате запросов, так что:
var someEvent = session.CreateCriteria<Event>().SetMaxResults(1).UniqueResult<IEvent>();
Console.WriteLine(someEvent.Title);
Чтобы сделать это, я пытаюсь настроить nhibernate receptor для создания динамических микшинов. За исключением того, что это не работает, и я не знаю почему. Вот настройка, как я могу ее упростить.
Вот событие:
class Event : IEventEntity {
//ID and props here
public IList Translations {get; set;}
}
IEvenEntity
Также имеет Getter и Setter для списка. Есть также EventTranslation
класс, который очень прост и реализует IEventTranslation
наиболее очевидным способом.
Карта бегства для события:
class EventMap : ClassMap<Event>{
//obvious ID and properties stuff here...
HasMany<EventTranslation>(x => x.Translations);
}
Работает прекрасно само по себе-я могу запрашивать события и перейти к их переводам. Я почти уверен, что картирование хорошее.
Я основывал форму моего перехватчика на очень крутой руководство Крзиштоф Кецмик за то, что он сделал что -то немного связанное. Во -первых, я создал суперинтерфейс, который собираюсь реализовать с помощью динамического прокси:
public interface IEvent : IEventEntity, IEventTranslation{}
Вот мой NH -перехватчик. Очевидно, я взламываюсь как сумасшедший:
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;
}
}
Где Dyninterceptor - это перехватчик, который фактически выполняет работу по вопросам вступления в сумку в отношениях, получения правильного перевода и возврата правильной ценности. Детали не слишком актуальны, потому что их никогда не вызывается.
После завязывания в NH Interceptor я вижу, что он работает, и на самом деле NH получает актерский состав IEvent
Правильно (т.е. прокси, по крайней мере, создается). Но по какой -то причине это полностью испортит увлажнение сущности:
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
Мне кажется, что это не работает, потому что NH использует отражение, чтобы установить свойство, но, конечно, целевой тип неверен, потому что я поменял IEVENT на мероприятие. Есть ли способ обойти это?
Кроме того, что касается основного подхода, есть ли лучший способ сделать это в NH?
Решение
Хорошо, так что для того, насколько сложно я задал этот вопрос, он оказывается довольно простым, и если бы я знал достаточно, я мог бы задать вопрос «как я динамически заставить объект реализовать другой интерфейс, не теряя его типа? ". Ответ заключается в том, чтобы предоставить цель, как в
Type type = Type.GetType(clazz, false);
var mixin = (Event)gen.CreateClassProxy(type, new[] { typeof(IEvent) }, new DynInterceptor());
Другие советы
Я не уверен, но я думаю, что вы должны использовать фильтр в сочетании с EventListener, чтобы получить желаемый результат. Если вы установите фильтр в своей языковой таблице и используете eventlistener, чтобы включить фильтр до событий, которые вы хотите включить фильтрацию, вы можете получить желаемое поведение.