Java Desktop-App设计 - 带Hibernate的MVC

时间:2012-02-29 11:16:24

标签: java hibernate oop

我有一些关于我的Java应用程序的设计问题。 该软件是一个桌面应用程序,它使用MySQL数据库来存储不同类型的对象(客户,员工,文档)。每个员工都有一组客户,每个客户都包含许多文档。整个结构通过hibernate延迟加载。

我目前使用这四个层来构建我的应用程序

  • model - 包含数据的对象,例如客户,员工......
  • views - 每个操作的视图(添加客户,创建文档,......)
  • controller - 每个视图都有自己的控制器,用于控制一个或多个业务对象
  • 业务对象 - 封装模型上的操作逻辑(添加customer = customerBO,添加document = documentBO,...)

因此,当用户现在想要向客户添加新文档时,客户视图的控制器会打开一个新的 - 让我们称之为“文档窗口”,它有自己的控制器。 由于每个文档都必须属于客户,因此我将客户作为参数传递给客户。但是,如果我使用这种方式,我必须确保打开当前的hibernate会话,并将客户对象重新连接到会话以使用延迟加载。

现在我的问题是:有更优雅的方法吗?也许通过会话级来存储当前活跃的客户?或者我的结构中有一个错误,我没有看到?

2 个答案:

答案 0 :(得分:0)

这可能适用于数据传输对象或值对象。简而言之,在UI代码中为Customer使用只读,非休眠,分离的表示,而不是Hibernate创建的表示。此Customer对象将是您的UI所需的后端的完整Customer对象的最小投影。实际上,您可能不需要更多的名称和ID(当然取决于您的UI)。

在过去,我引入了一个“服务”界面,该界面仅适用于这些值对象或DTO(这些术语不是真正可互换,但我正在尝试要灵活,这是重要的概念: - ))。

在代表客户保存某些内容时,请调用服务组件service#attachDocument(customer.getCustomerId())或其他任何内容。该组件将与Hibernate交互以检索客户并调用customer.addDocument(documentId)(或适用于您的模型的任何内容)。

答案 1 :(得分:0)

首先,做这样的事情并不罕见:

DocumentService {
   public Document addDocument(int customerId) {
         Customer customer = session.getById(Customer.class, customerId);
         Document document = new Document();
         customer.getDocuments().add(document);
         session.update(customer);
         return document;
   }
}

因此,最后在添加文档之前阅读客户可能看起来像是一次性能损失,但如果您不想传递完整的Customer对象,那么这就是您的选择。

通常我会使用类似CustomerInfo对象的东西,它只存储一些相关的信息,如id,名称,地址等。通常,如果用户看到过时的数据,那些经常不变的东西并不重要。 (如果关键是经常使用通知事件/消息来更新相关的信息对象)。

现在您可以将这些CustomerInfo传递给许多常见的服务方法。如果从数据库加载了Customer对象,我通常会更新客户信息对象,以使其尽可能保持同步。

这里只有一条规则。由于客户信息可以包含陈旧数据(其他一些用户已经更改了它,因此您需要验证其有效性。您可以向其引入@Version或比较相关属性(如果已经更改)。(您使用乐观记录也称为长期用户事务和两个或多个短数据库事务。)

所以最后使用reattach没有错。

如果您有本地嵌入式数据库并且使用hibernate的应用程序是唯一的用户(单用户设置),您可能需要考虑使用单一会话方法,在该方法中同步或汇集对会话的每次访问以避免并发事务/访问数据库。

这样可以确保只有一个Object代表每个“数据库对象/行”。这使得很容易假设每个对象和每个Info都与数据库同步。只有会话丢失的情况下,您必须通过将应用程序使用的所有实体重新连接到新会话来进行恢复,以避免出现两个实体对象表示同一数据库行的情况,这在hibernate中是不允许的。

<强>摘要

  • 使用附件没有错。
  • 在应用程序中传递实体实例并没有错。
  • 请记住:Hibernate通常会发出一个select来刷新对象并验证它是否代表当前会话/事务所看到的当前db状态(使用@Version来降低成本)。
  • 您可以使用CustomerInfo / DocumentInfo对象来避免传递实体实例以减少内存占用并避免重新加载。
  • 如果性能是个问题,您可以直接使用id创建文档,然后使用您从insert(SQL)语句中选择的id创建DocumentInfo。这样您就不必重新加载用户或创建文档对象。这只是为了减少内存占用并提高性能,但接缝不是您的担忧。

我建议,只要你没有内存消耗问题就坚持重新安装。