Search code examples
c#sqlnhibernatesqldependencysyscache2

NHibernate SysCache2 - dependency breaks cache


Company class:

class Company {
  public virtual int Id { get;set;}
  public virtual string Name { get;set;}
  public virtual int IntProp { get;set;}
}

Companies table:

CREATE TABLE Companies (
  Id INT PRIMARY KEY,
  Name NVARCHAR(50) NOT NULL,
  IntProp INT NULL );

Here is my web.config:

<syscache2>
    <cacheRegion name="RefData"></cacheRegion>
    <cacheRegion name="Company">
        <dependencies>
            <commands>
                <add name="CompanyCommand"
                         command="SELECT * FROM Companies WHERE Deleted = 0"
        />
            </commands>
        </dependencies>
    </cacheRegion>
</syscache2>

Problem: other entities in the RefData cache region (which never change, think countries, etc.) are cached fine. Company, on the other hand, is not.


Solution

  • The solution consisted of solving multiple problems:

    1. IntProp was nullable on the table, and property was not nullable int. This led to NHibernate not being able to set NULLs when getting a row, so the property value became 0. When session flushed, it saw a modification (NULL to 0) and threw exceptions about modifying readonly data. (This is a NH design flaw, IMO)

    2. The dependency query SELECTs all columns (*), which is not supported by the dependency mechanism. Instead, each column has to be listed. (This fails quietly, which again is a SQL design flaw, IMO)

    3. The dependency query FROM clause has table name but omits the schema name, which is also not supported. Adding dbo. fixed it. I spent 4 hours to find this. (Again, quiet failure, SQL flaw)

    4. After going to production lane, user permission bugs appeared. Those can be fixed by following http://social.technet.microsoft.com/Forums/exchange/en-US/99321f54-1fef-4860-9fe9-5966a46fe582/once-for-all-right-permissions-for-sqldependency-please

    Hope this helps someone.

    PS. Per request, final result:

    class Company {
      public virtual int Id { get;set;}
      public virtual string Name { get;set;}
      public virtual int? IntProp { get;set;}
    }
    
    <syscache2>
        <cacheRegion name="RefData"></cacheRegion>
        <cacheRegion name="Company">
            <dependencies>
                <commands>
                    <add name="CompanyCommand"
                             command="SELECT Id, Name, IntProp FROM dbo.Companies WHERE Deleted = 0"
            />
                </commands>
            </dependencies>
        </cacheRegion>
    </syscache2>