Reputation: 978
I have the following problem. I've enabled the second level caching system on nHibernate (using Postgres) with the following configurations
cfg.SessionFactory().Caching.Through<RtMemoryCacheProvider>().WithDefaultExpiration(28800);
I'm enabling only enabling entity caching because i do not need query caching at this point.
In my entities here are my settings (they are some are read-write, some are read-only, more can be made read-only at this point)
<id name="StudentID" access="property" column="`StudentID`">
<generator class="native" />
</id>
<property name="Name" column="`Name`" >
<property name="Address" column="`Address`" />
<property name="IsActive" column="`IsActive`" />
<property name="DateCreated" column="`DateCreated`" />
<property name="DateLastUpdated" column="`DateLastUpdated`" />
<property name="LastUpdatedBy" column="`LastUpdatedBy`" />
<set name="Projects" inverse="true" mutable="false">
<cache usage="read-only"/>
<key column="`StudentID`" />
<one-to-many class="Project" />
</set>
<set name="Classes" inverse="true" mutable="false">
<cache usage="nonstrict-read-write"/>
<key column="`StudentID`" />
<one-to-many class="Class" />
</set>
<set name="Books" inverse="true" mutable="false">
<cache usage="nonstrict-read-write"/>
<key column="`StudentID`" />
<one-to-many class="Book" />
</set>
</class>
When unit testing my solution - i first pre-fetch a list of students, and then try to generate a cache hit
public bool PreLoadStudents()
{
using (ISession session = NHibernateHelper.OpenSession())
{
IList<Student> results = session.QueryOver<Student>()
.Fetch(d => d.Projects).Eager
.Fetch(d => d.Classes).Eager
.Fetch(d => d.Books).Eager
.TransformUsing(Transformers.DistinctRootEntity)
.List<Student>();
}
}
[Test]
public void GetByIdTest()
{
bool bLoaded = testBLL.PreLoadStudents();
var student1 = testBLL.GetByID("123");
var student2 = testBLL.GetByID("123");
long cacheHit = testBLL.GetSessionFactory().Statistics.SecondLevelCacheHitCount;
Assert.That(cacheHit,Is.EqualTo(2));
}
I've tried out two different implementation of "GetByID", one of them uses the convention "get" method, the other uses the query over method with fetch statements similar to the PreLoadStudents student method.
In the case of "get" method, both cache hit occurred and the test passes. In the case of "query over", no cache hit or misses occur, but 2 queries were executed instead.
Here's the code i used for the "GetByID" method using the "Get" method
var student = session.Get<Student>(studentId);
I do not prefer this method because i'm unable to fetch child collections that are lazy-loaded
Here's the code i used for the "GetByID" method using the "QueryOver" method
var student = session.QueryOver<Student>()
.Where(d => d.studentId == currentStudentId)
.Fetch(d => d.Projects).Eager
.Fetch(d => d.Classes).Eager
.Fetch(d => d.Books).Eager
.SingleOrDefault();
Any thoughts on why the "get" method generated a hit while the query over method did not?
Upvotes: 0
Views: 1762
Reputation: 978
After reading and doing some experimental testing, here's the solution that emerged for my question.
My initial question - Any thoughts on why the "get" method generated a hit while the query over method did not? is a mis-informed question, here's why:
Thus
Lessons learned
Upvotes: 2
Reputation: 11
Second-level cache only works if you have a transaction, which is also a good practice around queries anyway.
using (ISession session = NHibernateHelper.OpenSession())
using (ITransaction tx = session.BeginTransaction())
{
IList<Student> results = session.QueryOver<Student>()
.Fetch(d => d.Projects).Eager
.Fetch(d => d.Classes).Eager
.Fetch(d => d.Books).Eager
.TransformUsing(Transformers.DistinctRootEntity)
.List<Student>();
tx.Commit();
}
Upvotes: 1