持久有序域对象

时间:2011-02-16 14:37:59

标签: java hibernate web-applications orm domain-driven-design

许多Web应用程序中一个非常常见的用例是,用户可以在Web界面中对域对象进行排序 - 并且该命令会保留以供以后使用;但我注意到,每次我需要实现这一点时,我总是会提出一个不同的解决方案,并为一个简单的域对象增加了相当大的重量和复杂性。例如,假设我有持久性实体Person

Person {
   long id
   String name
}

用户前往/myapp/persons并按照他们获得补偿(或其他)的顺序查看系统中的所有人员 - 所有人都可以点击并拖放到另一个位置 - 当页面时再次加载,订单被记住。问题是关系数据库似乎没有一个很好的方法来做到这一点; ORM也不是(我使用的是休眠)

我一直在考虑使用通用排序方法 - 但是会有一些开销,因为数据会单独持久化,这可能会减慢某些用例的访问速度。我的问题是:有没有人想出一个非常好的方法来建模持久域对象的顺序?

我使用Hibernate或JDBCTemplate在JavaEE中工作 - 因此任何代码示例都将以这些技术为基础最有用。或者任何概念性的想法都会受到欢迎。

更新:我不确定我哪里出错了,但似乎我不清楚,因为大多数回复的回复都不符合我的问题(因为它在我脑海中)。问题不在于我如何在获取行时对行或列进行排序 - 这是域对象的顺序发生变化 - 有人点击并将“人”从列表底部拖到列表顶部 - 他们刷新页面和列表现在按照他们指定的顺序。

5 个答案:

答案 0 :(得分:1)

获取结果时,只需使用不同的ORDER BY子句构建HQL查询,具体取决于用户上次使用的内容

答案 1 :(得分:1)

  

问题是关系数据库似乎没有一个很好的方法来做到这一点; ORM也不是(我使用的是休眠)

我不确定你会在哪里得到这种印象。 Hibernate specifically has support for mapping indexed collections(这是另一个名称的“列表”),通常归结为在包含项目集合的表中存储“list-index”列。

直接从手册中获取的一个例子:

<list name="carComponents"
    table="CarComponents">
    <key column="carId"/>
    <list-index column="sortOrder"/>
    <composite-element class="CarComponent">
        <property name="price"/>
        <property name="type"/>
        <property name="serialNumber" column="serialNum"/>
    </composite-element>
</list>

这将允许List<CarComponents>与您的根实体相关联,存储在CarComponents表中,并带有sortOrder列。

答案 2 :(得分:1)

一种可能的通用解决方案:

创建一个表来保存排序信息,最简单的情况是每个实体有一个方向的可排序字段:

table 'sorts'
* id: PK
* entity: String
* field: String
* direction: ASC/DESC enumeration (or ascending boolean flag)

通过添加userId来执行每用户排序或添加带有外键的sort_items表以支持一次按多个字段排序,可能会使其变得更加复杂。

一旦您保持排序信息,就可以将Order实例添加到条件(如果这是您正在使用的内容)或将语句按顺序连接到HQL。

这也可以使您的实体自身免受有序信息的影响,在这种情况下听起来像是正确的方法,因为排序纯粹是出于用户交互的目的。

更新 - 保留实体订单 鉴于您希望能够重新排序实体,而不仅仅是为它们定义排序,那么您确实需要将序数或索引值作为实体定义的一部分。

问题,因为我确定你意识到需要更新的实体数量,最糟糕的情况是将最后一个实体移动到列表顶部。

您可以使用1以外的增量值(比如10),这样您就可以:

ordinal | name
10      | Crosby
20      | Stills
30      | Nash
40      | Young

大多数情况下,更新行将涉及选择两个项目并更新一个项目。如果我想将Young移动到位置2,我从数据库中选择当前项目2和前一项目以获得序数10和20.使用这些来创建新的序数((20 - 10)/ 2 + 10 = 15) 。现在以15的顺序对Young进行单次更新。

如果你达到二分之一与你刚刚加载的实体之一产生相同索引的程度,那就意味着它需要产生一个任务来根据原始增量标准化序数值。

答案 3 :(得分:0)

答案 4 :(得分:0)

我认为关系数据库不能比专用订购列做得更好。

除了游标之外,“订单”的概念并没有在SQL中真正定义,它们不是核心关系概念,而是实现细节。

据我所知,唯一要做的就是用@OrderColumn(JPA2,Hibernate 3.5+兼容)抽象排序列。