0

我刚刚阅读了我的一个 ASP.NET 页面的跟踪,我注意到每次需要用户时都会从数据库中加载页面用户。由于每个ISession都应该缓存对象,因此我对此感到非常困惑。

从逻辑上讲,问题肯定是以下两件事之一:

  1. ISession缓存无法正常工作
  2. 每次请求用户时,都会使用不同的方式加载ISession

我认为问题是2)。我正在使用 Castle Windsor 来管理对象生命周期,因此我发布了一些我正在使用的代码,以防有人可以帮助发现问题。温莎城堡管理的课程有:

  1. MooseUserRepository- 用于管理 MooseUser 实例的存储库类(即本例中的页面用户)
  2. KctcUnitOfWork- ISession 的包装器

MooseUserRepository有这样的构造函数依赖KctcUnitOfWork

public MooseUserRepository(IUnitOfWork unitOfWork)
    {

    }

配置文件如下所示:

<component id="KctcUnitOfWork" service="Kctc.BusinessLayer.Kctc.IUnitOfWork,Kctc.BusinessLayer" type="Kctc.NHibernate.Kctc.UnitOfWork,Kctc.NHibernate" lifestyle="PerWebRequest"/>
<component id="MooseUserRepository" service="Kctc.BusinessLayer.Kctc.Repositories.IMooseUserRepository,Kctc.BusinessLayer" type="Kctc.NHibernate.Kctc.Repositories.MooseUserRepository,Kctc.NHibernate" lifestyle="PerWebRequest"/>

注意PerWebRequest生活方式。

Castle Windsor 容器只是一种称为实用程序类的静态属性,Moose.Application因此它始终存在:

private static IWindsorContainer _windsorContainer;

    public static IWindsorContainer WindsorContainer
    {
      get
      {
        if (_windsorContainer == null)
        {
          _windsorContainer = new WindsorContainer(new XmlInterpreter(HttpContext.Current.Server.MapPath("~/CastleWindsorConfiguration.xml")));
        }
        return _windsorContainer;
      }
    }

页面本身有一个 IMooseUserRepository 实例,如下所示:

private IMooseUserRepository _mooseUserRepository;
private IMooseUserRepository MooseUserRepository
  {
    get
    {
      if (_mooseUserRepository == null)
      {
        _mooseUserRepository = Moose.Application.WindsorContainer.Resolve<IMooseUserRepository>();
      }
      return _mooseUserRepository;
    }
  }

页面的用户由如下所示的属性访问:

private MooseUser PageUser
  {
    get { return MooseUserRepository.Load(ApplicationSettings.UsernameFromWeb); }}

这些后续调用似乎PageUser导致了重复的 SQL 命令:

txtSubject.Enabled = PageUser.CanHandleLegalWorks;
    ddlDue.Enabled = PageUser.CanHandleLegalWorks;

现在显然我可以通过将加载的对象存储在私有变量中来解决这个问题MooseUser,但我的理解是ISession应该为我做这个。

任何人都可以冒险猜测出了什么问题吗?

4

4 回答 4

2

您声明以下内容:

从逻辑上讲,问题肯定是以下两件事之一:

  1. ISession 的缓存无法正常工作
  2. 每次请求用户时,都会使用
    不同的 ISession加载它

我认为您可能会将 Nhibernate 的第一(会话)级缓存与第二级缓存混淆。

会话的制造和丢弃都很便宜。在 Web 应用程序中,您通常会为每个请求使用一个会话。一旦你第一次获取或加载一个实体,它就会被放入一级缓存中,该缓存的范围是会话的生命周期。当 Session 在请求结束时关闭并处置时,您将无法再访问会话级缓存中的对象。事实上,每个用户都被不同的会话加载——这是完全正常的。

二级缓存的范围是会话工厂的生命周期。如果启用了二级缓存,一旦您通过其主键加载实体,它就会存储在二级缓存中,并且可以由所有会话访问而无需再次访问数据库,直到它从缓存中删除。您将需要在每个实体的基础上显式启用缓存。这是您正在寻找的行为。

进一步阅读:

编辑

您需要从NHContrib 项目中选择一个缓存提供程序。您可能想要使用 Asp.Net 缓存的 SysCache2,但如果您愿意,可以使用 MemCached 或 Velocity 或其他几个。我还建议您尝试一下Nhibernate Profiler。我发现它在深入了解 Nhibernate 正在做什么方面非常宝贵。

于 2011-01-07T15:41:31.067 回答
1

就像您在问题中注意到的那样,您正在为存储库使用 PerWebRequest 生活方式,因此将在每个请求上重新创建 ISession(由存储库使用)。我发现这种行为是正确的,应该在每个请求上创建 ISession,并且应该处理 NH 上的每个操作。

如果您想将一个 ISession 用作单例,则应将存储库生活方式声明为单例。

我认为您的应用程序中应该有某种 SessionProvider o SessionFactory,也许您可​​以针对单例会话进行处理。

高温高压

于 2011-01-07T15:16:45.137 回答
1

我已经找出了问题所在,这是一个非常微妙的问题。

我正在使用以下代码检索用户:

private MooseUser PageUser
  {
    get { return MooseUserRepository.Load(ApplicationSettings.UsernameFromWeb); }
}

ApplicationSettings.UsernameFromWeb就 ASP.NET 而言,检索当前用户的用户名。用户的用户名是用户表的自然键,但它不是主键!据我所知,一级缓存仅适用于通过主键检索的对象。

编辑: 我通过创建一个属性来解决这个问题,该属性将加载的用户填充到 HttpContext.Current.Items 中,并在根据本文加载之前先检查那里

于 2011-01-07T15:23:52.167 回答
1

在这种情况下,您可以在映射中使用natural-id(Fluent NH 中的 NaturalId)绕过二级缓存过期。

于 2011-01-07T15:53:13.487 回答