Description
Please see the attached file for a reproducible project (also includes database script, and unit test)
FutureDoesNotLoadNoLazyChildNHibernate.zip
Steps to reproduce:
In the context of my example project, I have a Post
table and a Comment
table. A Post
has a one-to-many
relationship with Comment
. The PostMap
is configured to use CollectionLazy.NoLazy
for Comments.
I wrote four unit tests in the attached project to demonstrate an issue. I use Future
/FutureValue
to get Posts/Post, and I expected the related child Comments
to be loaded and usable outside the session. However, it throws a LazyInitializationException.
I then tried another approach using QueryOver.List
(which returns a list of entities) or QueryOver.SingleOrDefault
, and in this case, I can use the Comments
as expected.
Please see my comment below for the reason and discuss that. Thank you a lot.
public class TestLoadingNoLazy
{
private ISessionFactory _sessionFactory;
[OneTimeSetUp]
public void OneTimeSetUp()
{
var config = new Configuration();
config = config.DataBaseIntegration(db =>
{
db.ConnectionString = @"Server=localhost;Database=NoLazyNHibernate;Integrated Security=true;";
db.Dialect<MsSql2012Dialect>();
db.Driver<Sql2008ClientDriver>();
});
var mapper = new ConventionModelMapper();
mapper.AddMapping<PostMap>();
mapper.AddMapping<CommentMap>();
var hbmMappings = mapper.CompileMappingForAllExplicitlyAddedEntities();
config.AddMapping(hbmMappings);
_sessionFactory = config.BuildSessionFactory();
}
[OneTimeTearDown]
public void OneTimeTearDown()
{
_sessionFactory.Close();
}
[Test]
public void LoadListPosts__UsingFuture__ThrowLazyInitializationException()
{
// Arrange
IList<Post> postFuture;
using (var session = _sessionFactory.OpenSession())
{
postFuture = session.QueryOver<Post>()
.Where(x => x.Title == "Title")
.Future().ToList();
}
// Action
Func<string> action = () => postFuture[0].Comments[0].Content;
// Assert
action.Should().ThrowExactly<LazyInitializationException>();
}
[Test]
public void LoadListPosts__UsingList__LoadCommentsSuccessfully()
{
// Arrange
IList<Post> postList;
using (var session = _sessionFactory.OpenSession())
{
postList = session.QueryOver<Post>()
.Where(x => x.Title == "Title")
.List();
}
// Action
Func<string> action = () => postList[0].Comments[0].Content;
// Assert
action.Should().NotThrow();
}
[Test]
public void LoadOnePost__UsingFutureValue__ThrowLazyInitializationException()
{
// Arrange
Post postFutureValue;
using (var session = _sessionFactory.OpenSession())
{
postFutureValue = session.QueryOver<Post>()
.Where(x => x.Title == "Title")
.FutureValue().Value;
}
// Action
Func<string> action = () => postFutureValue.Comments[0].Content;
// Assert
action.Should().ThrowExactly<LazyInitializationException>();
}
[Test]
public void LoadOnePost__UsingSingleOrDefault__LoadCommentsSuccessfully()
{
// Arrange
Post postFutureValue;
using (var session = _sessionFactory.OpenSession())
{
postFutureValue = session.QueryOver<Post>()
.Where(x => x.Title == "Title")
.SingleOrDefault();
}
// Action
Func<string> action = () => postFutureValue.Comments[0].Content;
// Assert
action.Should().NotThrow();
}
}