nHibernate二级缓存无法进行查询

时间:2014-12-12 22:14:44

标签: c# postgresql caching nhibernate

我有以下问题。 我已经在nHibernate上启用了二级缓存系统(使用Postgres),具体如下 配置

cfg.SessionFactory().Caching.Through<RtMemoryCacheProvider>().WithDefaultExpiration(28800);

我只允许启用实体缓存,因为此时我不需要查询缓存。

在我的实体中,这里是我的设置(它们是一些是读写的,一些是只读的,此时更多可以是只读的)

       

<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>

在单元测试我的解决方案时 - 我首先预取一个学生列表,然后尝试生成 缓存命中

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));    
}

我尝试了两种不同的&#34; GetByID&#34;的实现,其中一种使用 会议&#34; get&#34;方法,另一个使用查询方法与fetch语句类似 到PreLoadStudents学生方法。

在&#34; get&#34;方法,发生缓存命中和测试通过。 在&#34;查询&#34;的情况下,没有发生缓存命中或未命中,而是执行了2个查询。

这是我用于&#34; GetByID&#34;的代码。方法使用&#34; Get&#34;方法

var student = session.Get<Student>(studentId); 

我不喜欢这种方法,因为我无法获取延迟加载的子集合

这是我用于&#34; GetByID&#34;的代码。使用&#34; QueryOver&#34;的方法方法

 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();

关于&#34; get&#34;方法生成了一个命中而查询方法没有?

2 个答案:

答案 0 :(得分:2)

在阅读并做了一些实验测试后,这是我的问题出现的解决方案。

我最初的问题 - 关于为什么“get”方法在查询方法时没有产生命中的任何想法?是一个误解的问题,原因如下:

  1. nHibernate中的二级缓存(L2)缓存实体的值
  2. nHibernate中的查询缓存缓存搜索结果的索引
  3. 因此

    1. 如果我们知道 id ,则允许我们快速检索实体。如果 我们不知道id然后我们将需要做一个将要命中的查询 如果以前没有运行数据库。替代方法是从缓存加载所有内容,然后在其上运行LINQ。
    2. 查询允许我们将查询结果存储在可以从L2缓存填充的查询缓存中。
    3. 经验教训

      1. 如果要缓存查询,请启用L2缓存和查询缓存,不使用L2查询缓存可能不会提高性能
      2. 只能使用缓存查询或GET
      3. 访问L2

答案 1 :(得分:1)

二级缓存仅在您有交易时才有效,这对于查询来说也是一种很好的做法。

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();
}