1

我正在解决一个问题,其中我有许多实体,每个实体都有一个对应的一对多翻译表,它指定实体字段的本地化版本。(所有这些都是我在其上添加地图的遗留模式)。例如:

  • 事件
    • ID
  • 事件翻译
    • 事件ID
    • 语言
    • 标题
    • 其他领域

所以,如果我要用希腊语呈现我的信息,我会加入这两个表并指定 Language = 'Greek' 并拥有所有正确的东西。

我正在尝试做的是构建即时混合,将正确的数据直接合并到单个对象中,并将其作为查询结果返回,例如:

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

为此,我正在尝试设置一个 NHibernate 拦截器来创建 DynamicProxy mixins。除了它不起作用,我不知道为什么。这是设置,尽我所能简化它。

这是事件:

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

IEvenEntity列表还有一个 getter 和 setter。还有一个EventTranslation类,它超级简单,并且IEventTranslation以最明显的方式实现。

Event的流畅地图:

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

单独工作正常——我可以查询事件并导航到他们的翻译。我很确定映射是好的。

我的拦截器形状基于 Krzysztof Koźmic 的一个非常酷的指南,用于做一些稍微相关的事情。首先,我创建了一个将使用动态代理实现的超级接口:

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 拦截器后,我看到它正在运行,实际上 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 换成了 Event。有没有办法解决这个问题?

另外,就基本方法而言,在新罕布什尔州有更好的方法吗?

4

2 回答 2

1

好的,所以对于我提出的这个问题有多复杂,事实证明它非常简单,如果我足够了解,我可以问这样一个问题:“我如何动态地使一个对象实现另一个接口而不丢失它的类型? ”。答案是提供一个目标,如

Type type = Type.GetType(clazz, false);
var mixin = (Event)gen.CreateClassProxy(type, new[] { typeof(IEvent) }, new DynInterceptor());
于 2011-06-27T18:07:17.860 回答
0

我不确定,但我认为你应该结合使用过滤器和事件监听器来获得你想要的结果。如果您在语言表上设置过滤器并使用事件侦听器在要启用过滤的事件之前启用过滤器,您可能会获得所需的行为。

于 2011-06-24T06:35:19.530 回答