【问题标题】:OfType<> not playing nicely with NHibernate Proxy classOfType<> 不能很好地与 NHibernate 代理类一起使用
【发布时间】:2014-04-11 16:58:42
【问题描述】:

我有类似于以下的课程:

public abstract class Base { }
public class Concrete : Base { }
public class Cement : Base { }

还有下面的代码

var bases = someEntity.Bases; // returns two Concrete and once Cement

// bases now contains:
// - ProxyBase : Base
// - Concrete : Base
// - Cement : Base

var concretes = bases.OfType<Concrete>(); 

// concretes only contains one Concrete (i.e. the ProxyBase is ignored)

我怎样才能获得两个Concretes 的预期结果,而不用 NHibernate 知识污染我的班级?

如果可能的话,我也不想强制映射不使用延迟加载。

【问题讨论】:

  • 如果OfType 没有返回值,我怀疑代理实际上是Concrete 的子类。 proxy.GetType().BaseType.FullName 的值是多少?

标签: c# nhibernate fluent-nhibernate


【解决方案1】:

这绝对是动态代理的痛点。您可以将 Self 属性添加到基类,以便获得对未代理对象的引用:

public virtual Base Self
{
    get { return this; }
}

那么你就可以通过检查类型得到某个类型的具体类了:

var concretes = bases.Where(b => b.Self is Concrete);

您还可以创建一个扩展方法,使 OfType 的行为符合预期:

public static IEnumerable<T> OfType<T>(this IEnumerable<Base> bases) where T : Base
{
    return Enumerable.OfType<T>(bases.Select(b => b.Self));
}

【讨论】:

  • 污染我的实体似乎是一种耻辱,但这绝对是最简单的方法——尤其是因为它根本不涉及 NH。
【解决方案2】:

您必须先取消代理才能获得具体类型。

public static T Unproxy<T>(this T obj, ISession session)
{
    if (!NHibernateUtil.IsInitialized(obj))
    {
        NHibernateUtil.Initialize(obj);
    }

    if (obj is INHibernateProxy)
    {    
        return (T) session.GetSessionImplementation().PersistenceContext.Unproxy(obj);
    }
    return obj;
}

然后

foreach(var base in bases)
      Unproxy<Concrete>(base);

【讨论】:

  • 您好,感谢您的回复。这意味着我的方法需要我不希望发生的 NHibernate 知识。
  • 然后创建一个封装NHibernate的类,这样它就不会知道NHibernate
【解决方案3】:

所以我找到了一个临时解决方案 - 但这很脆弱(如果 ToString 被覆盖,那么它会崩溃,其他 ORM 可能以不同的方式工作)并且绝不令人满意

var concreteTypeName = typeof(Concrete);

// yuck
var concretes = bases.Where(x => String.Equals(x.ToString(), concreteTypeName));

【讨论】:

    【解决方案4】:

    如果你可以使用INHibernateProxy,试试这个:

    var concretes = bases.Where(x => {
            var proxy = (INHibernateProxy)x;
            return proxy.HibernateLazyInitializer.PersistentClass == typeof(Concrete);
        });
    

    或者如Kirk Woll所说:

    var concretes = bases.Where(x => x.GetType().BaseType == typeof(Concrete));
    

    【讨论】:

      【解决方案5】:

      在测试正确的类型时,代理很痛苦。 这个answer 涵盖了所有不同的解决方案。

      1. 一种解决方案是使用no-proxy 延迟加载,这应该可以解决问题! (explanations)
      2. 如果您不能使用no-proxy(出于任何原因),我认为Jamie Ide answer 是最好的解决方案

      祝你好运!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-05-11
        相关资源
        最近更新 更多