You should create ViewModels that represent everything that the View needs to be rendered. You should not be issuing database queries from the view if at all possible. To summarize the link above here:
- It increase the time that the connection to the database have to be open. The recommendation is to keep that open only for the duration of the action, not throughout the lifetime of the request.
- It make it that much harder to understand what are the data requirements for a particular action is.
- When writing views, you shouldn't be bothered with thinking about persistence, or the number of queries that you views are generating.
- The views are often the most changeable parts in the application, and having the application issue queries from the views may result in significant changes to the way the application data access pattern between revisions.
- Most often, queries from the views result from lazy loading, Select N+1 or similar bad practices.
We strongly recommend that you'll avoid generating queries in the view, instead, perform all your queries in the action, and provide in memory access only to the view for them to render themselves.
(Emphasis on the last point mine).
The practical implications of this are that you should not be lazy loading anything in a view. So what should you do instead? This is where the ViewModel layer comes in. You should be fully populating a thin ViewModel with the information you need and then rendering the view with that.
Furthermore, ViewModels shouldn't even contain classes mapped with NHibernate (this appears to be what you're doing in your example).
With all this in mind I would change your current code:
public class CacheTestViewModel
{
public List<ProjectViewModel> Projects { get; set; }
}
public class ProjectViewModel
{
public string Owner { get; set; }
/* etc. */
}
.. And then your code to populate those ViewModels:
public CacheTestViewModel GetCacheTestViewModel()
{
var vm = new CacheTestViewModel();
var session = Repository.Session;
using (var tx = session.BeginTransaction())
{
var projects = Repository.Session.Query<Project>().Cacheable();
foreach (var project in project)
{
vm.Projects.Add(new ProjectViewModel { Owner = project.Owner.Name });
}
tx.Commit();
}
return vm;
}
Now you might be thinking "gee, that's a lot of code to map domain entities to ViewModels. I can see that getting out of hand." You'd be right about that. There's a library called AutoMapper that you can use to semi-automate your mappings.