Lazy proxy initialization fails after entity detachment in NHibernate
0 reputation · 24 Aug 2021, 19:56 UTC
0 reputation · 24 Aug 2021, 19:56 UTC
NHibernate creates uninitialized proxies for lazy-loaded associations. When the owning entity is still associated with an open session, accessing a proxy member triggers a SELECT to load the related data. The behavior changes once the entity becomes detached—either through session closure, eviction, or serialization.
Documentation states that a detached proxy cannot initialize because it lacks a session reference. However, the exact failure mode varies: some versions throw a LazyInitializationException, others return null or default values, and custom interceptors may alter the outcome. Applications that pass entities across transaction boundaries or serialize them for remote clients need predictable semantics.
ByteCode.LinFu or ByteCode.CastleWhich exception type or fallback behavior is guaranteed when a detached proxy member is accessed? Does second-level cache presence change the outcome? Are there supported patterns to safely materialize lazy associations before detachment without eager fetching?
35275 reputation · 24 Aug 2021, 23:29 UTC
Accessing an uninitialized lazy proxy on a detached entity in NHibernate always throws LazyInitializationException (or its NHibernate-specific equivalent NHibernate.LazyInitializationException). This is the defined contract across all supported proxy factories (ByteCode.LinFu, ByteCode.Castle, and the default ByteCode.Castle in modern versions). No version returns null or default values silently—custom interceptors can wrap or replace the exception, but the base behavior is an exception.
Enabling the second-level cache for the associated entity type does not allow a detached proxy to initialize. The cache stores entity data, not hydrated proxy instances. Proxy initialization requires an active ISession to:
Without a session, the proxy has no mechanism to reach the cache. The cache may satisfy the subsequent SELECT if a session is open, but it cannot substitute for the session itself.
Use one of these approaches inside the session scope before the entity becomes detached:
NHibernateUtil.Initialize(proxy)var order = session.Get<Order>(id);
NHibernateUtil.Initialize(order.Customer); // forces load
session.Close();
// order.Customer is now safe to accessFetch in Query (Not Eager Fetching Globally)var order = session.Query<Order>()
.Fetch(o => o.Customer)
.Single(o => o.Id == id);This loads the association in the same query without marking the mapping as eager.
session.Load<T>(id) + Immediate Accessvar customer = session.Load<Customer>(order.CustomerId);
var _ = customer.Name; // touches the proxy
session.Close();Load returns a proxy; accessing any property initializes it within the open session.
Are you using stateless sessions (ISessionFactory.OpenStatelessSession()) anywhere in the request pipeline? Stateless sessions do not support lazy loading at all and will throw immediately even before detachment.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.