0

我想编写一个用于在线学习的 Java EE 应用程序。我正在考虑这个数据表示:

@Entity
public class Course {
    private String name;
    private String[] instructors;
    private String[] teachingAssistants;
    private GradeBook gradeBook;

    // plenty of methods
}

@Entity
public class GradeBook {
    private GradeBookColumn[];

    // some methods
}

@Entity
public abstract class GradeBookColumn {
    private String name;
    private GradeBookColumnType type;

    // more methods
}

我会拥有更多的东西,但你明白了。

现在,在 EJB 3.2 规范中,实体 bean 已被移除并替换为 JPA 实体。我的问题是如何应对这种悲惨的损失。序列化的 JPA 实体对我不起作用的三个原因:

  1. 表现。我需要通过网络推送整个实体及其所有数据。有相当多的数据,并且可能需要很长时间才能完成所有这些数据。
  2. 安全。如果实体中的所有数据都通过网络传输,则下载它的程序可以访问所有数据。但是,我希望只有在用户具有足够权限的情况下才能访问某些数据。
  3. 写访问。下载数据副本后,客户端应该能够对其进行更改。但是,如果进行了更改,它们将不会持久保存到服务器。当然,我总是可以将实体发送回服务器进行持久化,但我必须通过更慢的上游连接发送所有数据。

那么,在没有实体 bean 的情况下,我如何设计这个系统来满足这些要求呢?

4

1 回答 1

1

我不确定实体 bean 的丢失是否真的很悲惨,但这是见仁见智 :)

您似乎在桌面上有一个连接到远程服务器的富客户端。你有两个选择:

A. 您在客户端和服务器之间交换“分离的”对象图。客户端接收一些数据,对其进行修改,然后将其发回。然后服务器“合并”它接收到的数据。加载数据时服务器上有一个事务,合并回来时有一个事务。为确保您没有冲突,您可以对数据进行版本控制。

B. 您使用“扩展的持久性上下文”。在这种情况下,客户端会收到仍然“附加”到会话的实体。客户端对实体的修改会被缓存,当你调用服务器上的方法时会同步。

因此,关于您面临的三个设计问题,以下是我的看法:

  1. 表现。JPA 和其他现代 ORM 依靠惰性来避免不必要的数据传输:数据按需加载。您可以选择图形的哪个部分可以急切或延迟加载。使用选项 A,您需要确保在将所有必要的数据发送到客户端之前加载它们;如果客户端尝试访问未加载的数据,则会收到异常,因为它在事务之外。使用选项 B,我猜客户端可以随时延迟加载数据(值得仔细检查)。

  2. 安全。JPA 实体应该是业务对象,而不是数据对象。它们可以封装进行必要检查并保留所需不变量的业务方法。换句话说:安全性不是在数据级别而是在业务逻辑级别处理的。这适用于选项 A 和 B。

  3. 写访问。使用选项 A,您需要发回整个图形并将其合并。使用选项 B,框架应该以更优化的方式合并已缓存的更改。

结论:

扩展的持久性上下文是为具有长工作单元的 GUI 应用程序设计的。他们理论上应该解决你的问题。在实践中,扩展的持久性上下文虽然有其复杂性(例如,需要使用有状态会话 bean)。

分离和合并图的方法更简单,但会引发您在性能方面提到的问题。

第三种选择是回到传统的数据传输对象 (DTO)以优化性能。在这种情况下,JPA 实体只保留在服务器端。您只需将真正需要的数据子集传输到 DTO 中,而不是传输 JPA 实体。缺点是 DTO 会激增,并且您将拥有样板代码来从 JPA 实体创建 DTO,并从 DTO 更新 JPA 实体。

于 2013-09-09T06:58:57.310 回答