OfType<>不能很好地使用NHibernate Proxy类

时间:2014-04-11 16:58:42

标签: c# nhibernate fluent-nhibernate

我的课程类似于以下内容:

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)

如何在不使用NHibernate知识污染我的课程的情况下获得两个Concrete的预期结果?

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

5 个答案:

答案 0 :(得分:4)

这绝对是动态代理的痛点。您可以将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));
}

答案 1 :(得分:0)

您必须首先取消它以获取具体类型。

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

答案 2 :(得分:0)

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

var concreteTypeName = typeof(Concrete);

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

答案 3 :(得分:0)

如果你可以使用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));

答案 4 :(得分:0)

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

  1. 一种解决方案是使用no-proxy延迟加载,这应该可以解决! (explanations
  2. Jamie Ide answer是我无法使用no-proxy(出于任何原因)的最佳解决方案
  3. 祝你好运!