NHibernate / Castle.ActiveRecord ;会话管理;窗体
我的第一个真正的(不是测试的)NHibernate/Castle.ActiveRecord 项目正在快速开发。 我现在正在使用 NHibernate/Castle.ActiveRecord 大约一个月,但仍然不知道如何在我的 WindowsForms 应用程序中处理会话。
常见的处理方法接缝对我不起作用:
- SessionPerRequest、SessionPerConversation 等都只适用于 WebApplications 等。
- 当我正确时,SessionPerApplication 不推荐/非常危险
- SessionPerThread 不是很有帮助,因为我要么只有一个线程、WindowsForms 线程,或为每个按钮单击一个新线程。第一件事会让我的应用程序使用太多内存并在内存中保存旧对象。通过单击 ech 按钮的工作线程,我将禁用延迟加载,因为我加载的对象的寿命比线程长。
- SessionPerPresenter 也不起作用,因为很常见,我在表单中打开一个“子演示者”,让用户搜索/加载/选择一些引用的对象(外键),并且导致演示者被破坏 - 这意味着什么会话已关闭 - 但“超级演示者”中使用的对象来填充引用属性(foreigen key)。
我已经使用谷歌和必应几个小时并阅读了很多内容,但只找到了一个关于我的案例的好网站:http://msdn.microsoft.com/en-us/magazine/ee819139.aspx。这里使用了 SessionPerPresenter,但对于“子演示者”来说,它只给出了 id,而不是整个对象!看起来这个例子中没有外来键,也没有将对象返回到“超级呈现者”的场景。
问题
- Windowsforms/桌面应用程序还有其他会话处理方法吗?
- 我可以向我的所有演示者添加会话属性或会话构造函数参数,但在我的 ui 代码中进行会话处理感觉不太合适。
- 当异常发生时,NHibernate 希望我终止会话。但如果它“只是”一个业务逻辑异常而不是一个 NHibernate 异常呢?
示例
我正在尝试制作一个示例来涵盖我的大部分问题。
// The persisten classes
public class Box
{
public virtual int BoxId{get;set;}
public virtual Product Content{get;set;}
...
}
public class User
{
public virtual int UserId{get;set;}
public virtual IList<Product> AssigenedProducts{get;set;}
...
}
public clas Product
{
public virtual int ProductId{get;set;}
public virtual string PrductCode{get;set;}
}
。
// The presenter-classes
public class ProductSearchPresenter : SearchPresenter<Product> { ... }
public class ProductEditPresenter : EditPresenter<Product> { ... }
public class UserSearchPresenter : SearchPresenter<User> { ... }
public class UserEditPresenter : EditPresenter<User> { ... }
public class BoxSearchPresenter : SearchPresenter<Box> { ... }
public class BoxEditPresenter : EditPresenter<Box> { ... }
// The search-presenters allow the user to perform as search with criterias on the class defined as generic argument and to select one of the results
// The edit-presenters allow to edit a new or loaded (and given as parameter) object of the class defined as generic argument
现在我有以下用例,所有用例都可以在同一个应用程序中同时异步执行(使用只需在演示者之间切换)。
- 使用 BoxSearchPresenter 的实例来搜索并选择对象
- 此用例的一部分是使用 ProductSearchPresenter 的实例来填充 BoxSearchPresenter 的条件
- 此用例的一部分是使用 BoxEditPresenter 的实例来编辑和保存 BoxSearchPresenter 实例的选定对象
- 此用例的一部分是使用 BoxEditPresenter 的实例来使用实例 UserSearchPresenter 来搜索并选择对象
- 此用例的一部分是使用 UserEditPresenter 的实例来编辑和保存 UserSearchPresenter 的选定对象
- 此用例的一部分是使用 ProductSearchPresenter 搜索并选择将添加到 User.AssignedProducts 的对象。
- 使用 ProductSearchPresenter 的实例来搜索和选择对象。
- 此用例的一部分是使用 ProductEditPresenter 的实例来编辑和保存 ProductSearchPresenter 的选定对象。
这只是一小部分用例,但我已经遇到了很多问题。
- UseCase 1. 和 2. 在同一个 ui 线程中同时运行。
- 用例 1.1。和2.2。将选定的对象返回给其他演示者,这些演示者使用该对象的时间比已加载该对象的演示者存在的时间更长。
- 用例 3.1。可能会改变从 2.2./1.1 加载的对象。 3.1之前。开始了,但是当2.2./1.1.在 3.1 之前提交。完成后,对象将被保存,并且不可能“回滚”3.1。
my first real (not test) NHibernate/Castle.ActiveRecord project is developing quickly.
I am working with NHibernate/Castle.ActiveRecord about one month now but still have not a real idea how to handle Sessions in my WindowsForms application.
The common handling-methods seam not to work for me:
- SessionPerRequest, SessionPerConversation, etc. all only work for WebApplications, etc.
- SessionPerApplication is not recomanded/highly dangerous when I am correct
- SessionPerThread is not very helpfull, since I either have only one thread, the WindowsForms-thread, or for each button-click a new thread. The first thing would make my applicaton use too much memory and to hold old objects in the memmory. With worker-threads for ech button click I would disable lazy-loading, since my loaded objects would live longer then the thread.
- SessionPerPresenter is not working as well, because it is common, that I open a "sub-presenter" in a form to let the user search/load/select some referenced objects (foreigen key) and of cause the presenter is destroyed - what means session closed - but the object used in the "super-presenter" to fill the referencing property (foreigen key).
I've used google and bing for hours and read a lot, but only found one good website about my case: http://msdn.microsoft.com/en-us/magazine/ee819139.aspx . There SessionPerPresenter is used, but to a "sub-presenter" it is only given the id, not the entire object! And it seams that there are no foreigen-keys in this example and no scenari in wich a object is returned to a "super-presenter".
Qestions
- Is there any other method of session handling for windowsforms/desktop-application?
- I could add a session-property or a session-constructor-parameter to all of my presenters, but it feels not right to have session-handling all over my ui-code.
- When an Exception occures NHibernate want's me to kill the session. But if it is 'only' a business-logic exception and not an NHibernate-Exception?
Example
I am trying to make an example the covers most of my problem.
// The persisten classes
public class Box
{
public virtual int BoxId{get;set;}
public virtual Product Content{get;set;}
...
}
public class User
{
public virtual int UserId{get;set;}
public virtual IList<Product> AssigenedProducts{get;set;}
...
}
public clas Product
{
public virtual int ProductId{get;set;}
public virtual string PrductCode{get;set;}
}
.
// The presenter-classes
public class ProductSearchPresenter : SearchPresenter<Product> { ... }
public class ProductEditPresenter : EditPresenter<Product> { ... }
public class UserSearchPresenter : SearchPresenter<User> { ... }
public class UserEditPresenter : EditPresenter<User> { ... }
public class BoxSearchPresenter : SearchPresenter<Box> { ... }
public class BoxEditPresenter : EditPresenter<Box> { ... }
// The search-presenters allow the user to perform as search with criterias on the class defined as generic argument and to select one of the results
// The edit-presenters allow to edit a new or loaded (and given as parameter) object of the class defined as generic argument
Now I have the following use-cases, wich all can be performed in the same application at the same time asyncronous (the use simply switchs between the presenters).
- using an instance of BoxSearchPresenter to search and select a object
- part of this usecase is to use an instance of the ProductSearchPresenter to fill a criteria of the BoxSearchPresenter
- part of this usecase is to use an instance of the BoxEditPresenter to edit and save the selected object of the BoxSearchPresenter-instance
- using an instance of UserSearchPresenter to search and select a object
- part of this usecase is to use an instance of the UserEditPresenter to edit and save the slected object of the UserSearchPresenter
- part of this usecase is to use a ProductSearchPresenter to search and select objects that will be added to User.AssignedProducts.
- Using an instance of ProductSearchPresenter to search and select a object.
- part of this usecase is to use an instance of ProductEditPresenter to edit and save a selected object of the ProductSearchPresenter.
It's only a small collection of usecases, but there are allready a lot of the problems I have.
- UseCase 1. and 2. run at the same time in the same ui-thread.
- UseCase 1.1. and 2.2. return there selected objects to other presenters that use this objects longer then the presenters exist that have loaded the object.
- UseCase 3.1. might alter a object loaded from 2.2./1.1. before 3.1. was started, but when 2.2./1.1. is commited before 3.1. is finished the object would be saved and it would not be possible to "rollback" 3.1.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
以下是我发现最适合我们的 WinForms 应用程序架构(基于 MVP)的简短视图。
每个演示者都是依赖于它需要的存储库的构造函数,例如,如果您有 InvoicePresenter,那么您有 InvoiceRepository 作为依赖项,但您可能会有 CustomerRepository 和许多其他依赖项,具体取决于复杂性(CustomerRepsitory 用于将所有客户加载到客户组合框中,如果您想要更改发票的客户,诸如此类)。
然后,每个存储库都有一个 UnitOfWork 的构造函数参数。您可以使用 UnitOfWork 模式抽象会话,也可以让存储库依赖于 ISession。
一切都通过 IoC 容器连接在一起,我们在其中根据“上下文”创建演示者。这是一个非常简单的概念,上下文是每个演示者和所有子演示者,我们又将其创建为更复杂的演示者的复合块以降低复杂性(例如,如果您有多个选项卡来编辑某些实体或其他内容)。
因此,在实践中,此上下文 90% 的时间是基于表单的,因为一种表单至少是一个演示者/视图。
因此,回答您的问题:
每个演示者的会话和每个对话的会话(也适用于 WinForms)在这里只是真正可用的模式(并且在各处打开结束会话,但不是处理该问题的好方法)-< /p>
这是最好的解决方案通过使存储库依赖于会议,而不是演讲者。您使演示者依赖于存储库,存储库依赖于会话,当您创建所有存储库时,您为它们提供公共会话;但正如我再次指出的,这只有在上下文中完成时才实用。您不能共享演示者编辑发票的会话和另一演示者编辑客户的会话;但是您可以在通过主演示者和发票详细信息以及发票注释子演示者编辑发票时共享会话。
请澄清,不明白这个...
Here is just a short view of what I found best to fit into our WinForms application architecture (based on MVP).
Every presenter is constructor dependent on repositories which it needs, for example if you have InvoicePresenter then you have InvoiceRepository as dependency, but you will probably have CustomerRepository and many others depending on complexity (CustomerRepsitory for loading all customers into the customers combobox if you want to change customer of the invoice, stuff like that).
Then, every repository has a constuctor argument for UnitOfWork. Either you can abstract the session with UnitOfWork pattern, or you can have your reporitories depend on ISession.
Everything is wired together by IoC container, where we create presenters based on "context". This is a very simple concept, context is per presenter and all sub presenter, which in turn we create as composite block of more complex presenters to reduce complexitiy (if for example you have multiple tabs of options to edit some entity or something).
So, in practice, this context is 90% time form based, because one form is at least one presenter / view.
So to answer your questions:
Session per presenter and session per conversation (works with WinForms as well) are only really usable patterns here (and opening closing sessions all over the place, but not really good way to handle that)-
this is best solved by making repositories depend on session, not presenters. You make presenters depend on repositories, repositories depend on session, and when you create all, you give them common session; but as I state again, this is only practical when done in contexts. You cannot share session for presenter editing invoices and another presenter editing customers; but you can share session when editing invoice via main presenter and invoice details and invoice notes sub presenter.
Please clarify, didn't understand this...