java - 设计具有外键关系的 DTO

标签 java orm dto object-model

我正在为 Web 应用程序使用 Java + Spring 框架。我没有使用任何 ORM 工具。相反,我尝试使用简单的 DAO/DTO 模式将数据库关系建模为 Java 对象。每当 DTO 与数据库中的单个表完全对应时,它就非常简单。但是如果有表使用外键引用其他表,我不确定最好的方法是什么。在 Stackoverflow 中寻找类似的答案,但找不到符合我需要的答案。我想举一个非常具体的例子——假设有两个实体用户和组。我有一个 User DTO 和 Group DTO,每个都有 UserDao(JdbcUserDao) 和 GroupDao(JdbcGroupDao)。

现在我在数据库中有一个连接用户和组的关系。一个用户可以属于多个组。表名为 User_Group_Association,具有以下 DB 定义:

用户ID |群组编号

这里的user_id是指向user表的外键。同样group_id 指的是组表。当我用 Java 为这个 DTO 建模时,我应该做这样的事情吗:

public class UserGroupAssoc {
    private int userId;
    private int groupId;

    //Setters and getters follow
}

或者应该是这样的:

public class UserGroupAssoc {
    private User user;
    private Group group;

    //Setters and getters follow
}

特定的 UI 用例:我想显示用户名及其所属的相应组名。像这样的——

名称 -> 组名

Keshav -> 管理员、最终用户、报告管理员
Kiran -> ReportAdmin
Pranav -> 最终用户

在 DTO 设计的第一种方法中,我需要再次从数据库中获取用户详细信息(名称)和组详细信息(名称)。在第二种方法中,我需要在构建 UserGroupAssoc 对象本身时获取 User 和 Group 对象。

在可能的第三种方法中,我可以按如下方式设计 UserGroupAssoc DTO:

public class UserGroupAssoc {
    private String userName;
    private String groupName;
    private int userId;
    private int groupId;

    //Setters and getters follow
}

在这第三种方法中,我在 SQL 中连接表以仅获取用例所需的字段,然后相应地为 DTO 建模。

实现这种情况的标准方法是什么?在 DTO 设计中连接表是否合适?有观点认为一个DTO应该只对应一张表,关联的对象应该聚合在app层。这有从数据库中获取多个对象的开销吗?对正确的方法太困惑了,抱歉解释这么长!

最佳答案

免责声明:我不是 ORM 专家...

...但在经典中many-to-many relations您不需要第三个数据模型 (UserGroupAssoc)。 User 类将包含一组 Group:

public class User {
   // ... user fields ...
   List<Group> groups;
   // ... getters/setters ...
}

如果您还需要反向关系(一个组包含用户),Group 类将如下所示:

public class Group {
   // ... group fields ...
   List<User> users;
   // ... getters/setters ...
}

同样,经典的做法是在集合(UserGroup 而不是 userId groupId)。

只有在关联表 (User_Group_Association) 包含除 user_idgroup_id 之外的其他内容(可能是一些授权)时,您通常才需要第三个域对象允许将用户添加到组的代码,无论如何):

user_id | group_id | auth_code

在这种情况下,UserGroupAssoc 类可能具有以下结构:

public class UserGroupAssoc {
    private User user;
    private Group group;
    private String authorizationCode;

    // ... setters/getters ...
}

UserGroup 之间的多对多关系将转换为与这个新领域对象的两个多对一关系。通常优先使用域对象(UserGroup 而不是 userIdgroupId)。

Which is the standard approach to achieve this scenario?

好吧,如果您使用的是 ORM 框架,那将是该框架执行此操作的标准方式。但是因为您有自定义的 ORM 解决方案,所以很难说。

Is joining tables alright in the DTO design?

为什么应用层的DTO设计要受数据库联表的影响?这是 object-relational impedance mismatch 的案例也许还有 law of leaky abstraction因为您无法将关系域完全抽象为保持 1:1 对应关系的对象域。

Some have opinions that one DTO should correspond to only ONE table and the associated objects should be aggregated in the app layer. That has overhead of doing multiple object fetches from DB right?

ORM 有一些局限性(对于您可能遇到的某些问题,请再次参阅对象关系阻抗不匹配)并且很难对您的域对象进行建模以适应关系数据库的约束,反之亦然。报告是这方面的一个很好的例子。

一份报告通常会聚合来自多个表格的数据。这对于某些 SQL 连接当然没有问题,但是您将如何将结果映射到 DTO?正如你自己所说...

Whenever the DTO exactly corresponds to a single table in the database, it is very straight forward

...但是报告结果不会映射到单个表,它必须映射到更多表的片段。

根据您在应用程序中的需求,您最终可能会得到一些看起来很奇怪的类或看起来很笨拙的 SQL。您最终可能会运行比获取正确的对象模型和它们之间的关联所需的更多的查询;或者您可能有更多类似的 DTO,只是为了限制访问数据库的次数并获得更好的性能。

所以我想说的是(再次声明我不是 ORM 专家)并不是所有的应用程序都适合 ORM;但如果您考虑继续使用它,可以查看 Hibernate/JPA 如何解决这些问题,或者甚至继续使用它们。

关于java - 设计具有外键关系的 DTO,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8769606/

相关文章:

java - java中number/10和number*0.1的区别

java - 背景图像不工作 javaFX

java - 哈希表中的内存地址作为哈希。为什么HasTable不能使用Key的实际内存地址作为Hash?

symfony - 如何在 ORM Doctrine2 中手动设置/保留主键

java - "orphanRemoval = true"删除操作时未删除子对象

java - SLF4J Logger 有时会清除控制台输出(不需要)

php - 如何使 Laravel Eloquent "IN"查询?

asp.net-mvc - 在数据库上执行读取和创建/更新时使用实体和 DTO

nestjs - 在 NestJS 上将 DTO 与 multipart/form-data 一起使用时出现空对象

java - Spring Pageable 排序暴露了 dao 的内部命名