我正在尝试弄清楚如何在 ASP.NET Web 应用程序中完成存储库模式的实现。
目前,我为每个域类定义了一个存储库接口,用于定义方法,例如加载和保存该类的实例。
每个存储库接口都由一个执行 NHibernate 功能的类来实现。 Castle Windsor根据web.config将类的DI整理到界面中。下面提供了一个已实现类的示例:
public class StoredWillRepository : IStoredWillRepository
{
public StoredWill Load(int id)
{
StoredWill storedWill;
using (ISession session = NHibernateSessionFactory.OpenSession())
{
storedWill = session.Load<StoredWill>(id);
NHibernateUtil.Initialize(storedWill);
}
return storedWill;
}
public void Save(StoredWill storedWill)
{
using (ISession session = NHibernateSessionFactory.OpenSession())
{
using (ITransaction transaction = session.BeginTransaction())
{
session.SaveOrUpdate(storedWill);
transaction.Commit();
}
}
}
}
正如前面的线程所指出的,存储库类需要接受工作单元容器(即 ISession),而不是在每个方法中实例化它。
我预计工作单元容器将在需要时由每个 aspx 页面创建(例如,在属性中)。
当 Windsor 为我创建工作单元容器实例时,如何指定将其传递到 StoredWillRepository 的构造函数中?
或者这种模式完全错误?
再次感谢您的建议。
大卫
I'm trying to work out how to complete my implementation of the Repository pattern in an ASP.NET web application.
At the moment, I have a repository interface per domain class defining methods for e.g. loading and saving instances of that class.
Each repository interface is implemented by a class which does the NHibernate stuff. Castle Windsor sorts out the DI of the class into the interface according to web.config. An example of an implemented class is provided below:
public class StoredWillRepository : IStoredWillRepository
{
public StoredWill Load(int id)
{
StoredWill storedWill;
using (ISession session = NHibernateSessionFactory.OpenSession())
{
storedWill = session.Load<StoredWill>(id);
NHibernateUtil.Initialize(storedWill);
}
return storedWill;
}
public void Save(StoredWill storedWill)
{
using (ISession session = NHibernateSessionFactory.OpenSession())
{
using (ITransaction transaction = session.BeginTransaction())
{
session.SaveOrUpdate(storedWill);
transaction.Commit();
}
}
}
}
As pointed out in a previous thread, the repository class needs to accept an unit of work container (i.e. ISession) rather than instantiating it in every method.
I anticipate that the unit of work container will be created by each aspx page when needed (for example, in a property).
How do I then specify that this unit of work container instance is to be passed into the constructor of StoredWillRepository when Windsor is creating it for me?
Or is this pattern completely wrong?
Thanks again for your advice.
David
发布评论
评论(3)
我有一个基于 NHibernate 构建的持久性框架,在一些 Web 应用程序中使用。它将 NH 实现隐藏在
IRepository
和IRepository
接口后面,并使用 Unity 提供的具体实例(因此理论上我可以将 NHibernate 替换为 Entity)框架相当容易)。由于 Unity 不支持(或者至少我使用的版本不支持)除了依赖注入本身之外的构造函数参数的传入,因此不可能传入现有的 NH ISession;但我确实希望 UOW 中的所有对象共享相同的 ISession。
我通过使用一个控制存储库类来解决这个问题,该类在每个线程的基础上管理对 ISession 的访问:
在此示例中,
PersistenceFrameworkContext.Current.Items
访问IList
然后,我有
BeginUnitOfWork
和EndUnitOfWork
方法来处理 UOW - 我明确禁止嵌套 UOW,因为坦率地说,管理起来很痛苦。最后,一对方法提供对特定于域类型的存储库的访问:(
这里,
PersistentObject
是提供 ID 和 Equals 支持的基类。)因此,对给定存储库的访问是在 然后,该模式
被外观化,以便您可以使用
给定类型有专门存储库的情况(即需要的内容超出了从
IRepository
可以获得的内容),然后我创建一个从IRepository
,一个继承自我的IRepository
实现的扩展实现,在域类型本身中,我使用Repository
覆盖静态Repository
属性code>new(
MyApplication
[在实际产品中被称为不太令人讨厌的东西] 是一个外观类,负责通过 Unity 提供Repository
实例,因此您不依赖于域类中的特定 NHibernate 存储库实现。)这为我提供了通过 Unity 实现存储库实现的完全可插入性、在代码中轻松访问存储库而无需跳过任何环节,以及透明的每线程
ISession管理。
还有比上面更多的代码(并且我已经大大简化了示例代码),但您已经了解了总体思路。
在我的 Web 应用程序中,我有每个请求的会话,因此在
BeginRequest
和EndRequest
中调用BeginUnitOfWork
和EndUnitOfWork
> 分别。I have a persistence framework built on top of NHibernate that is used in a few Web apps. It hides the NH implementation behind an
IRepository
andIRepository<T>
interface, with the concrete instances provided by Unity (thus I could in theory swap out NHibernate for, say, Entity Framework fairly easily).Since Unity doesn't (or at least the version I'm using doesn't) support the passing in of constructor parameters other than those that are dependency injections themselves, passing in an extant NH ISession isn't possible; but I do want all objects in the UOW to share the same ISession.
I solve this by having a controlling repository class that manages access to the ISession on a per-thread basis:
In this example,
PersistenceFrameworkContext.Current.Items
accesses anIList<object>
that is stored eitherThreadStatic
if not in a Web context, or withinHttpContext.Current.Items
if it is in a Web context (to avoid thread-pool problems). The first call to the property instantiates theISession
from the stored factory instance, subsequent calls just retrieve it from storage. The locking will slow things down slightly but not as much as just locking an appdomain-scoped staticISession
instance.I then have
BeginUnitOfWork
andEndUnitOfWork
methods to take care of the UOW - I have specifically disallowed nested UOWs because frankly they were a pain to manage.Finally, a pair of methods provide access to the domain-type-specific repositories:
(Here,
PersistentObject<T>
is a base class providing ID and Equals support.)Access to a given repository is thus in the pattern
This is then facaded over such that you can use
Where a given type has a specialised repository (ie needs more than it can get from
IRepository<T>
) then I create an interface deriving fromIRepository<T>
, an extending implementation inheriting from myIRepository<T>
implementation, and in the domain type itself I override the staticRepository
property usingnew
(
MyApplication
[which is called something less noddy in the real product] is a facade class which takes care of supplying theRepository
instance via Unity so you have no dependency on the specific NHibernate repository implementation within your domain classes.)This gives me full pluggability via Unity for the repository implementation, easy access to the repository in code without jumping through hoops, and transparent, per-thread
ISession
management.There's lots more code than just what's above (and I've simplified the example code a great deal), but you get the general idea.
In my Web app, I have session-per-request, so
BeginUnitOfWork
andEndUnitOfWork
get called inBeginRequest
andEndRequest
respectively.我有一个与你的非常相似的结构,这是我解决你的问题的方法:
1)为了在每个方法上指定我的容器,我有一个单独的类(“SessionManager"),然后我通过静态属性调用它。通过这样做,下面是使用我的 Save 实现的示例:
2) 我的容器不是在每个 ASPX 页面上创建的。我在 global.asax 页面上实例化了我所有的 NHibernate 优点。
** 更多的事情出现了 **
3) 你不需要有一个助手来实例化 Load。您不妨使用 Get 而不是 Load。更多信息@ Load 和 Get 之间的区别。
4)使用当前的代码,您必须为您需要的每个域对象(StoredWillRepository、PersonRepository、CategoryRepository 等?)重复几乎相同的代码,这看起来很麻烦。您很好地使用通用类 通过 NHibernate 进行操作,例如:
在我的实现中,我可以使用 类似于:
I have a pretty similar structure to yours, and here's how I solve your question:
1) To specify my container on each method, I have a separate class ("SessionManager") which I then invoke via a static property. By doing so, here's an example using my Save implementation:
2) My container is not created on each ASPX page. I instantiate all of my NHibernate goodness on the global.asax page.
** A few more things spring up **
3) You don't need to have a helper to instantiate the Load. You might as well use Get instead of Load. More information @ Difference between Load and Get.
4) Using your current code, you would have to repeat pretty much the same code for each domain object you need (StoredWillRepository, PersonRepository, CategoryRepository, etc..?), which seems like a drag. You could very well use a generic class to operate over NHibernate, like:
In my implementation, I could then use something like:
从技术上讲,我的问题的答案是使用container.Resolve的重载,它允许您将构造函数参数指定为匿名类型:
但是让我们面对现实吧,其他人提供的答案信息丰富得多。
Technically, the answer to my question is to use the overload of container.Resolve which allows you to specify the constructor argument as an anonymous type:
But let's face it, the answers provided by everyone else have been much more informative.