不确定';是';nHibernate代理的行为

本文关键字:不确定 nHibernate 代理 | 更新日期: 2023-09-27 18:02:06

我有一种情况,我需要确定继承的类是否是特定的继承类,但模型中预期的类型是基类,并且它是使用nHibernate/Fluent nHibernate使用Table Per Concrete Class层次结构存储的。所以我的结构看起来有点像。。

class Mutation : Entity {
   virtual Aspect Aspect { get; set; }
   virtual Measurement Measurement { get; set; }
}
abstract class Measurement : Entity {
   // does nothing on its own, really.
}
class Numeric : Measurement {
   virtual int Value { get; set; }
   // may have some other properties
}
class Observable : Measurement {
  virtual Aspect Aspect { get; set; }
}

所以基本上,这里发生的事情是这样的。Mutation希望指向一种类型的数据和Measured更改(可能有其他方法可以更改数据,而不仅仅是平面数字(。因此,我将有一个对象,它只期望一个IList<Mutation>,并将每个后续类型的Measurement映射到它自己的特定表,与基本Measurement类共享Identity。到目前为止效果不错。

现在,Observable的不同之处在于,它不存储自己的值,而是再次指向另一个可能有自己一组突变和变化的Aspect。其思想是,该值将始终从预期的源中检索,而不是作为平面值保存在数据库中。(想要这种行为超出了这个问题的范围是有原因的(

所以,我的想法基本上是进行这样的评估。。

foreach(var measurement in list) {
   if(measurement is Observable){
      // then we know to lookup the other value
   }
}

那没用。我仍然只得到MeasurementProxy的代理结果。但是,在不使用nHibernate的情况下,相同的代码在独立的C#应用程序中运行良好,所以我非常确信问题出在代理上。

然后,我将以下方法添加到我的基本Entity类中。。。

        /// <summary>
        /// Unwrap the type from whatever proxy it may be
        /// behind, returning the actual .NET <typeparamref name="System.Type"/>.
        /// </summary>
        /// <returns>
        /// A pure <typeparamref name="System.Type"/> that is no longer proxied.
        /// </returns>
        public virtual Type Unwrap() {
            return GetType();
        } 

现在,如果我做Console.WriteLine(measurement.Unwrap());,我会得到正确的类型,但相同的评估。。。

foreach(var measurement in list) {
   if(measurement.Unwrap() is Observable){
      // then we know to lookup the other value
   }
}

仍然不起作用。它从不运行。有人能帮我吗?

不确定';是';nHibernate代理的行为

这是因为Unwrap()返回一个Type,所以measurement.Unwrap() is Observable将始终是false,而measurement.Unwrap() is Type将永远是true

使用运算符类型和引用相等:

if (measurement.Unwrap() == typeof(Observable)) {
    // Then we know to lookup the other value.
}

Hamidi答案中的检查是不够的。一旦您在映射中添加了一些惰性属性,例如:

<property name="Description" type="StringClob" not-null="false" lazy="true"/>

Unwrap方法将失败,因为对于使用惰性属性的类型,对象始终是代理,并且检查

if (measurement.Unwrap() == typeof(Observable)) {
    // Then we know to lookup the other value.
} 

将失败,因为"展开"将返回代理的类型,而不是预期的类型。

我使用以下方法来检查实体类型:

public virtual Type GetEntityType()
{
    var type = GetType();
    // Hack to avoid problem with some types that always be proxy. 
    // Need re-evaluate when upgrade to NH 3.3.3
    return type.Name.EndsWith("Proxy") ? type.BaseType : type;
}
public virtual bool IsOfType<T>()
{
    return typeof(T).IsAssignableFrom(GetEntityType());
}

检查变为:

if (measurement.IsOfType<Observable>()) {
    // Then we know to lookup the other value.
}

正如你在代码注释中看到的,这是对NH 3.1和Castle Proxy的破解:Castle Dynamic Proxy类型总是以Proxy结尾,所以我利用这个签名来检测对象是否是代理。我的项目仍然使用NH3.1,所以我不确定NH3.3需要对方法进行什么更改。