【问题标题】:NHibernate Session Custom DataNHibernate 会话自定义数据
【发布时间】:2015-06-12 23:40:25
【问题描述】:

我想做的是在我为 NHibernate 配置的 Save、Update、Delete 侦听器中拥有当前用户 ID。

在我看来,最好的方法是将此信息插入到 ISession 对象中,并在侦听器中读取此信息。但是好像没有地方可以做。

一种方法是实现接口,但是,我找不到任何可以继承的示例或基类(ISession 的成员太多)。完成实现后,我知道侦听器可以进行类型转换并获取用户 ID。

该应用是带有 Sql Server 2008 的 ASPNET MVC2。

【问题讨论】:

    标签: nhibernate


    【解决方案1】:

    如果您使用每个线程的会话,您可以将其存储在线程静态字段中:

    [ThreadStatic]
    private static int userId;
    
    public static void UserId { get { return userId; } set { userId = value; } }
    

    为避免线程池将值从一个会话传递到另一个会话,您应该在事务结束时重置该值(例如在事务提交事件中)。

    注意:我这样做非常成功。但我已经把它包裹在一些服务后面。只有一个 ThreadStatic 字段,其中包含一个自制的 TransactionContext,其中包含会话和我需要的所有其他数据。


    当您通过自己的方法访问会话时,您可以改用 SessionContext 类。它需要更改调用者,但您不必包装会话。

    类似这样的:

    public class ISessionContext : IDisposable
    {
      public ISession Session { get; }
    
      public SessionData Data { get; }
    }
    
    public ISessionContext CreateSession()
    {
      return new SessionContext(SessionFactory.OpenSession(), new SessionData(user));
    }
    

    【讨论】:

    • 不好,因为 ISession 是您在侦听器中获得的,这是我需要 SessionData 对象的地方。对不起。
    【解决方案2】:

    我有同样的问题,但我的情况不同:

    我有一个NHibernateSessionManager 处理ISessionITransaction

    然后我在NHibernateSessionManager 中使用CallContext.SetData 来保存编辑器实体,然后我使用CallContext.GetDataIPreUpdateEventListenerIPreInsertEventListenerIPreDeleteEventListener 中检索它

    CallContext 文档:

    http://msdn.microsoft.com/en-us/library/system.runtime.remoting.messaging.callcontext.aspx

    在网络环境中我使用HttpContext.Current.Items

    【讨论】:

      【解决方案3】:

      我想我想得更好。

      我刚刚创建了一个实现 NHibernate.ISession 的包装器,所以在我的方法中:

      public NHibernate.ISession OpenDataSession(int userId)
      {
        return new SessionWrapper(SessionFactory.OpenSession(), userId, this);
      }
      

      这样,在我的监听器中,我只需对 SessionWrapper 进行类型转换并获取 UserId 属性。

      到目前为止效果很好,我的包装器也实现了 IDisposable,所以应该没问题。

      如果有人知道得更好,请告诉我。

      更新:根据要求提供更多见解。

      SessionWrapper 类定义:只需实现 NHibernate.ISession 并将所有方法重新映射到 WrappedSession(构造函数的第一个参数),如:

          public DataStoreSessionWrapper(NHibernate.ISession wrappedSession, UserSession currentUser)
          {
          }
      
          public NHibernate.EntityMode ActiveEntityMode
          {
            get { return WrappedSession.ActiveEntityMode; }
          }
      
          public NHibernate.ITransaction BeginTransaction(System.Data.IsolationLevel isolationLevel)
          {
            return WrappedSession.BeginTransaction(isolationLevel);
          }
      

      这个想法是,通过使用 Ninject,您可以将 NHibernate.ISession 绑定到这个包装器。虽然这假设 UserSession 对象也可以被容器访问,这是真的,因为 UserSession 可以存储在 Session 包中。

      UPDATE2(随着我的发展:D):我有另一种方法,我认为这更好。

      我没有包装器,而是有一个接口 IUserSessionStore,它基本上只有一个方法:返回 UserSession 对象的 GetUserSession()。这个接口在所有需要这个信息的类的构造函数中。

      通过 Ninject,我简单地将这个接口映射到一个名为 UserSessionStore_ASPNETSession 的类,该类通过将对象存储到 ASPNET 会话包中来实现这一点。

      显然,我假设这是一个网站,所有内容都在一个层中(不涉及远程处理或 wcf)。

      我相信这实现起来更干净、更快捷,而且它还有益于可能需要此信息的所有其他层。

      谢谢!

      【讨论】:

      • 如果您还是通过自己的方法访问会话,您可以创建一个 SessionContext 类,该类包含会话和数据。我会在我的回答中告诉你。
      • 这怎么行??当您在列表器中进行转换时,您应该得到一个异常:类似于 Unable to cast object of type 'NHibernate.Impl.SessionImpl' to type SessionWrapper
      • @KatLimRuiz 请你提供你的 SessionWrapper 实现?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多