NHibernate 2.1升级至5.5后ISession.Load创建代理失败问题
NHibernate 5.5升级后ISession.Load创建代理失败问题
问题详情
从NHibernate 2.1升级至5.5版本后,应用构建运行正常,数据库实体读写无问题,但调用ISession.Load时抛出代理创建失败异常:
Creating a proxy instance failed at NHibernate.Proxy.StaticProxyFactory.GetProxy(Object id, ISessionImplementor session) at NHibernate.Event.Default.DefaultLoadEventListener.CreateProxyIfNecessary(LoadEvent event, IEntityPersister persister, EntityKey keyToLoad, LoadType options, IPersistenceContext persistenceContext) at NHibernate.Event.Default.DefaultLoadEventListener.ProxyOrLoad(LoadEvent event, IEntityPersister persister, EntityKey keyToLoad, LoadType options) at NHibernate.Event.Default.DefaultLoadEventListener.OnLoad(LoadEvent event, LoadType loadType) at NHibernate.Impl.SessionImpl.FireLoad(LoadEvent event, LoadType loadType) at NHibernate.Impl.SessionImpl.Load(String entityName, Object id) at NHibernate.Impl.SessionImpl.Load[T](Object id) INNER EXCEPTION: Sequence contains more than one matching element at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source, Func`2 predicate) at NHibernate.Proxy.ProxyBuilderHelper.GenerateMethodSignature(String name, MethodInfo method, TypeBuilder typeBuilder) at NHibernate.Proxy.NHibernateProxyBuilder.ImplementCallMethodOnImplementation(TypeBuilder typeBuilder, MethodInfo method, FieldInfo lazyInitializerField, Type parentType) at NHibernate.Proxy.NHibernateProxyBuilder.CreateProxiedMethod(TypeBuilder typeBuilder, MethodInfo method, FieldInfo lazyInitializerField, Type parentType) at NHibernate.Proxy.NHibernateProxyBuilder.CreateProxyType(Type baseType, IReadOnlyCollection`1 baseInterfaces) at NHibernate.Proxy.StaticProxyFactory.CreateProxyActivator(ProxyCacheEntry pke) at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory) at NHibernate.Proxy.StaticProxyFactory.GetProxy(Object id, ISessionImplementor session)
异常根源在于NHibernate代理生成逻辑中,ProxyBuilderHelper.GenerateMethodSignature方法使用SingleOrDefault获取泛型参数的类约束时,发现存在多个符合条件的类约束:
var typeConstraints = typeArg.GetGenericParameterConstraints() .ToArray(x => ResolveTypeConstraint(method, x)); var baseTypeConstraint = typeConstraints.SingleOrDefault(x => x.IsClass);
调用代码的泛型约束仅指定了基类:
public TEntity GetProxy<TEntity>(Guid id) where TEntity : Entity { ... return Session.Load<TEntity>(id); }
解决方案
检查实体类及继承链的泛型约束
排查TEntity对应的实体类、其继承的基类、实现的接口中,是否存在某个泛型方法/接口的泛型参数带有多个隐式类约束(比如基类继承了另一类,同时接口又对泛型参数添加了类约束,导致传递后出现多个类约束的情况)。切换代理生成器
替换默认的静态代理生成器为Castle动态代理:- 安装
NHibernate.Bytecode.CastleNuGet包 - 在NHibernate配置中添加:
configuration.SetProperty(NHibernate.Cfg.Environment.ProxyFactoryFactoryClass, typeof(NHibernate.Bytecode.Castle.CastleProxyFactoryFactory).AssemblyQualifiedName);
- 安装
升级NHibernate版本
该问题可能是5.5版本的已知bug,尝试升级到5.5.x的最新补丁版本,或直接升级到5.6及以上稳定版本,看是否已修复该代理生成逻辑的问题。清理实体类的冗余泛型约束
检查实体类中的泛型方法,确保没有出现多个类约束的情况(C#语法不允许显式定义,但可能存在旧代码的特殊写法或反射生成的异常类型),如有则调整为单一类约束。
内容的提问来源于stack exchange,提问作者Mud
相关产品推荐
相关产品推荐

