使用休眠命名查询和弹簧填充 DTO 的列表属性

Posted

技术标签:

【中文标题】使用休眠命名查询和弹簧填充 DTO 的列表属性【英文标题】:Fill a DTO's List attribute with hibernate named query and spring 【发布时间】:2012-12-19 16:58:16 【问题描述】:

我想知道是否可以通过休眠实现以下目标。考虑以下 DTO:

public class ClassDTO 
    private String className;
    private List<String> studentNames;
    //getters & setters

以及以下包含 sql 查询的 hbm 文件:

<hibernate-mapping>
    <class name="app.ClassDTO">
        <id name="className" type="java.lang.String" />
        <property name="studentNames" type="java.lang.List" />
    </class>

    <sql-query name="classQuery">
        <return alias="class" class="app.ClassDTO" />
            select classTable.CLASS_NAME AS class.className, ST.STUDENT_NAME
             from CLASS classTable
            join STUDENT ST on ST.CLASS_ID=classTable.CLASS_ID
            where ST.age<18
    </sql-query>
</hibernate-mapping>

如果我们在数据库中运行查询,我们将得到以下结果:

+----------+------------+
|CLASS_NAME|STUDENT_NAME|
+----------+------------+
|  CS106   |   BILL     |
|  CS106   |   GEORGE   |
|  CS106   |   MICHEL   |
|  ELEC8   |   WILL     |
|  ELEC8   |   MIKE     |
|  ELEC8   |   BETTY    |
+----------+------------+

如果我们在 hibernate 中运行查询,我们应该得到一个 ClassDTO 对象的列表。但是是否可以通过以下方式初始化这些对象?

List<ClassDTO> result = getHibernateTemplate.findByNamedQuery("classQuery").;
resul.size(); //<-- the list size should be 2 (one entry for CS106 and another for ELEC8)
result.get(0).getStudentNames().size(); //<-- the size should be 3 for BILL, GEORGE and MICHEL who are linked to the class CS106

我已经搜索过休眠文档,但我还没有成功找到任何答案。任何帮助真的很感激。 在此先感谢各位。

【问题讨论】:

我正在寻找的是某种分组操作,它将选择不同的班级名称,并用每个班级的多个学生姓名填充他们的studentLists 这不是经典的一对多关系吗?还是我错过了什么?网络上的几个例子:mkyong.com/hibernate/hibernate-one-to-many-relationship-example,viralpatel.net/blogs/hibernate-one-to-many-xml-mapping-tutorial 等。我认为这些例子中显示的休眠映射更好,更接近休眠。他们将“许多”部分作为一个集合,我认为这应该不是问题。 你给我的例子实际上是关于具有一对多关系的实体,我所拥有的是一个 DTO(不持久),我只是想这样填充它。班级和学生 entities(我的问题中没有显示)当然还有其他我不感兴趣的属性。 【参考方案1】:

如果您进一步规范化数据并调整映射,您可以让 Hibernate 自动执行此操作:

<class name="app.ClassDTO">
    <id name="className" type="java.lang.String" />
    <list name="studentNames" table="class_student">
    <key column="class_name" />
        <element type="string"/>
    </list>
</class>

我承认,如果唯一存在的数据确实是这两列,那么规范化似乎很愚蠢。但在很大程度上,让 Hibernate 自动将平面表数据转换为复杂的对象结构需要遵循某些规则(在这种特殊情况下,我不会称其为最佳实践)。

如果你想保持原样,那么你需要自己创建 ClassDTO,这真的不是那么难:

final List<Object[]> resultObjects = getSession().getNamedQuery().list();
public Map<String, ClassDTO> resultMap = new HashMap<>(String, ClassDTO);
for (Object[] result : resultObjects) 
    // find ClassDTO in map for class, or create new one
    // add student name to class dto instance

【讨论】:

以上是关于使用休眠命名查询和弹簧填充 DTO 的列表属性的主要内容,如果未能解决你的问题,请参考以下文章

如何将休眠查询的结果映射到 DTO 对象?

Spring - 使用休眠和弹簧安全扩展类

使用 Like 和 % % 运算符的休眠命名查询?

休眠弹簧连接无法自动装配

休眠中命名查询的优点?

弹簧或休眠连接泄漏