OfType<>;与NHibernate代理类玩得不好
本文关键字:代理 NHibernate lt gt OfType | 更新日期: 2023-09-27 17:58:06
我有类似于以下的类:
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)
如何在不污染我的课堂的情况下获得两个Concrete
的期望结果?
如果可能的话,我也不想强迫映射不使用延迟加载。
这无疑是动态代理的一个痛点。您可以将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));
}
您必须先取消它的氧气,才能获得具体的类型。
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);
所以我找到了一个临时解决方案,但这是脆弱的(如果ToString
被覆盖,那么它就会崩溃,其他ORM可能会以不同的方式工作),而且绝对不能满足
var concreteTypeName = typeof(Concrete);
// yuck
var concretes = bases.Where(x => String.Equals(x.ToString(), concreteTypeName));
如果您可以使用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));
在测试正确的类型时,代理是一个难题。这个答案涵盖了所有不同的解决方案。
- 一种解决方案是使用
no-proxy
延迟加载,这应该可以做到!(说明) - 在我看来,如果你不能使用
no-proxy
(出于任何原因),Jamie Ide的答案是最好的解决方案
祝你好运!