我想做的是在我为NHibernate配置的Save、Update、Delete监听器中拥有当前用户id。
在我看来,最好的方法是在ISession对象中插入此信息,并在侦听器中读取此信息。但似乎没有任何地方可以做这件事。
一种方法是实现接口,但是,我找不到任何可以从中继承的示例或基类(ISession有太多成员)。一旦我完成了实现,我就知道监听器可以进行类型转换并获得用户id。
该应用程序是带有Sql Server 2008的ASPNET MVC2。
如果每个线程使用一个会话,则可以将其存储在线程静态字段中:
[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));
}
我遇到了同样的问题,但我的情况不同:
我有一个NHibernateSessionManager
,它处理ISession
、ITransaction
等
然后我在NHibernateSessionManager
中使用CallContext.SetData
来保存编辑器实体,然后在IPreUpdateEventListener
、IPreInsertEventListener
、IPreDeleteEventListener
中使用CallContext.GetData
来检索它
CallContext文档:
http://msdn.microsoft.com/en-us/library/system.runtime.remoting.messaging.callcontext.aspx
在web上下文中,我使用HttpContext.Current.Items
我觉得我想得更好。
我刚刚创建了一个实现NHibernate.ISession的包装器,所以在我的方法中:
public NHibernate.ISession OpenDataSession(int userId)
{
return new SessionWrapper(SessionFactory.OpenSession(), userId, this);
}
通过这种方式,在我的监听器中,我只需向SessionWrapper键入cast并获取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包中。
更新2(随着我的发展:D):我有另一种方法,我认为更好。
我所拥有的不是包装器,而是一个接口IUserSessionStore,它基本上只有一个方法:GetUserSession(),它返回UserSession对象。此接口位于所有需要此信息的类的构造函数中。
通过Ninject,我只需将这个接口映射到一个名为UserSessionStore_ASPNETSession的类,该类通过将对象存储到ASPNET会话包中来实现这一点。
很明显,我假设这是一个所有东西都在一个层次上的网站(不涉及远程处理或wcf)。
我相信这更干净、更快地实现,它也有利于所有其他可能需要这些信息的层。
谢谢!