对于我们的Web应用程序(ASP.NET),我们使用Fluent NHibernate(2.1.2)进行二级缓存,不仅用于实体,还用于查询(使用条件API生成查询)。我们使用Session-Per-Request模式和一个SessionFactory应用程序范围,因此缓存服务于所有Nhibernate-Sessions。
问题:
我们必须在遗留数据库(Oracle)中的数据对象上处理每个用户的不同“Access-Rigths” - 也就是说,视图限制每个用户权限的返回数据。 因此存在这样的情况,例如,我们的条件使用相同的查询查询相同的视图,但返回不同的结果集,具体取决于用户权限。
现在,为了获得性能,缓存了上述查询。但这给我们带来了一个问题,即当查询首先从用户A的操作中触发时,它会缓存生成的ID,即用户A具有访问权限的ID。不久之后,从用户B的操作触发相同的查询,然后Nhibernate从第一次调用(来自用户A)中选择缓存的ID,并尝试获取用户B没有访问权限的相应实体(或者可能不适用于所有人)。我们正在检查事件监听器的权限,因此我们的应用程序会在上述情况下抛出访问权限异常。
思想:
不缓存查询可能是一个选项。但是在我们的应用程序中,性能是一个很明显的问题,因此用户可以更好地使用缓存查询。
我们甚至考虑过每个用户的SessionFactory,每个用户都有一个缓存。但这显然对资源有影响,有点过分,老实说不是一种选择,因为 有些实体,必须由多个用户(想到用户组)进行访问和操作,在“单个缓存”中创建陈旧数据的问题,等等。所以这是不行的。
什么是有效的解决方案?对于这种情况,是否有类似“最佳实践”的内容?
观
昨天我被困在这里,没有出路,我睡过了,今天我想出了某种“黑客”。
当NHibernate通过查询文本和参数(“子句”)缓存查询时,我想到了一种方法,在查询的签名中“走私”用户依赖的东西,所以它会 缓存每个用户的每个查询,但不会改变查询本身(关于查询的结果)。
所以“创造力”引导我去做这个(示例代码):
string userName = GetCurrentUser();
ICriteria criteria = session.CreateCriteria(typeof (EntityType))
.SetCacheable(true)
.SetCacheMode(CacheMode.Normal)
.Add(Expression.Eq("PropertyA", 1))
.Add(Expression.IsNotNull("PropertyB"))
.Add(Expression.Sql(string.Format("'{0}' = '{0}'", userName)));
return criteria.List();
这一行:
.Add(Expression.Sql(string.Format(“{0} = {0}”,userName)))
产生一个where子句,它总是计算为true,但是从Nhibernate的角度“更改”查询,因此它按单独的“userName”进行缓存。
我知道,这有点难看,我对此并不满意。 有人知道任何替代方法吗?
提前感谢。