在过去的几个月里,我一直在努力在我们的一个ASP.NET MVC(Web API)Web服务项目中实现NHibernate。我正在使用NHibernate 3.3.1,并且我已经针对该版本的NHibernate下载并编译了SysCache2,因为它听起来像是我们需要的最佳匹配。我们这个Web服务的目标是让它为多个其他Web应用程序提供员工数据,从而允许我们将这些信息缓存在一个中心位置,并减少对员工数据库的冗余查询拦截。
我偶然发现了它,并使SqlDependency工作得相当好。当我对记录进行更改时,我在NHibernate日志中看到了一个DependencyChanged事件,并从数据库中获取了一个新的副本。当我删除数据库中的一行时出现问题:SqlDependency似乎没有将此信息传达给SysCache2,因为如果我尝试运行将返回已删除记录的查询(如果它没有被删除),我会得到典型的来自NHibernate的“不存在具有给定标识符的行”。这就像NHibernate没有意识到该行已被删除。
我为添加到缓存表的新行获得了类似的行为。新行没有出现在常规轮询间隔(5秒),通常需要几分钟(我还没弄清楚是什么原因导致它在几分钟后突然出现)。
我想我可能错过了我的配置中的一个步骤,因为我已经从大约200个不同的线程拼凑起来,人们已经在谈论他们的SysCache& SqlDependency配置。我确定我丢失了一些块,可能还有一些不必要的块。如果有任何关于设置SysCache2和/或SqlDependency的全面参考,我当然没有找到它,并且可以在那里使用一些指针。我有很多关于配置的问题(例如我应该如何设置我的缓存区域,因为我目前在数据库中的每个表都有一个区域似乎很傻),但是现在最紧迫的问题是“没有行给定的标识符“exception。
这是我完整的NHibernate配置(流畅):
var config = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008
//.ShowSql()
.ConnectionString(s => s.FromConnectionStringWithKey("HumanResourceConnection"))
.DefaultSchema("dbo"))
.Cache(c => c
.UseSecondLevelCache()
.UseQueryCache()
.ProviderClass<SysCacheProvider>())
.Mappings(m =>
m.AutoMappings.Add(AutoMap.AssemblyOf<Employee>(new AutomappingConfiguration()).Conventions
.AddFromAssemblyOf<DataAccessPropertyConvention>()
.UseOverridesFromAssemblyOf<LocationMappingOverride>()))
.ExposeConfiguration(c =>
c.LinqToHqlGeneratorsRegistry<DataAccessLinqToHqlGeneratorsRegistry>())
.ExposeConfiguration(c =>
c.AppendListeners(
ListenerType.PreUpdate,
new IPreUpdateEventListener[] { new AuditEventListener() }))
.ExposeConfiguration(c =>
c.AppendListeners(
ListenerType.PreInsert, new IPreInsertEventListener[] { new AuditEventListener() }));
这是我们上面引用的DataAccessClassConvention类,它可能是您可能需要查看的唯一类。这将查看正在创建的每个映射,查找我们创建的属性以定义实例应映射到的缓存区域,并设置该属性。它还可以在具有该自定义属性的任何实例上启用缓存。模式行用于不在连接字符串指向的数据库中的对象。
/// <summary>
/// Default Class Convention for all dataobjects
/// </summary>
public class DataAccessClassConvention : IClassConvention
{
public void Apply(IClassInstance instance)
{
// Maps last element of namespace to database name
instance.Schema(instance.EntityType.Namespace.Substring(instance.EntityType.Namespace.LastIndexOf('.') + 1) + ".dbo");
// Enable second-level caching if a cache region is specified.
var attributeArray = (CacheRegionAttribute[]) instance.EntityType.GetCustomAttributes(typeof(CacheRegionAttribute), false);
if (attributeArray.Length > 0)
{
// Enable caching.
instance.Cache.ReadWrite();
// Set cache region for SqlDependency.
var attribute = attributeArray.First();
instance.Cache.Region(attribute.CacheRegion);
}
}
}
以下是我的web.config中的SqlDependency部分:
<sqlCacheDependency enabled="true" pollTime="5000">
<databases>
<add name="HumanResource" connectionStringName="HumanResourceConnection" />
</databases>
</sqlCacheDependency>
以下是我的一个缓存区域的示例,它们几乎完全相同:
<cacheRegion name="EmployeeRegion" relativeExpiration="86400">
<dependencies>
<commands>
<add name="Employee" command="SELECT employee_id from dbo.Employee" />
</commands>
</dependencies>
</cacheRegion>
我错过了什么?