设计具有外键关系的DTO

时间:2012-01-07 12:15:21

标签: java orm dto object-model

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

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

user_id | GROUP_ID

这里user_id是引用用户表的外键。类似地,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 - > Admin,EndUser,ReportAdmin
Kiran - > ReportAdmin
Pranav - > EndUser

在第一种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应该只对应一个表,关联的对象应该在应用层聚合。这有从DB进行多个对象提取的开销吗?对于正确的方法感到困惑,抱歉这么长的解释!

1 个答案:

答案 0 :(得分:6)

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

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

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

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

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

同样,经典的做法是在集合中使用“域对象”(您的DTO)(UserGroup而不是userId和{{1} })。

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

group_id

在这种情况下,user_id | group_id | auth_code 类可能具有以下结构:

UserGroupAssoc

public class UserGroupAssoc { private User user; private Group group; private String authorizationCode; // ... setters/getters ... } User之间的多对多关系将转换为与此新域对象的两个多对一关系。通常,首选使用域对象(GroupUser而不是GroupuserId)。

  

实现此方案的标准方法是什么?

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

  

在DTO设计中加入表格是否合适?

为什么应用层中的DTO设计会受到数据库中表的连接的影响?这是object-relational impedance mismatch的情况,也可能是law of leaky abstraction,因为您无法将关系域完全抽象为保持1:1对应关系的对象域。

  

有些人认为一个DTO应该只对应一个表,相关对象应该在应用层聚合。这有从DB进行多个对象提取的开销吗?

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

报告通常汇总来自多个表的数据。对于某些SQL连接,这当然没有问题,但是如何将结果映射到DTO?正如你自己说的那样......

  

每当DTO完全对应于数据库中的单个表时,它就非常直接

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

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

所以我想说的是(我不是ORM专家的免责声明)并非所有应用程序都是ORM的良好候选者;但如果你考虑继续它,可以看看Hibernate / JPA如何解决问题,甚至继续使用它们。