10

在我的 Wicket+JPA/Hibernate+Spring 项目中,大部分功能都基于收件箱页面,在该页面中,使用许多过滤选项(并非必须使用所有选项),用户可以限制他们想要使用的对象集. 我想知道实现这种过滤的最佳策略是什么?在此应用程序的旧版本中,搜索查询是通过连接包含 SQL 条件的字符串构建的。最近我读到了 JPA 提供的新 Criteria API - 你会推荐这个而不是使用搜索字符串吗?以及这如何与 DAO 层相结合——在业务层中使用 Criteria API 构建搜索查询不是违反层分离吗?

4

3 回答 3

4

对于像您描述的过滤查询,我绝对推荐使用 Hibernate 或 JPA 标准 API,因为它支持条件查询。我通常只是将标准构造代码放在我的 DAO 中,并在那里传递所有必需的(可能为 null)参数。

下面是使用 Hibernate 标准 API 的示例汽车租赁应用程序中的示例 DAO 方法:

public List<VehicleRentalContract> list(Long contractID,
            String customerNameOrID, Date date,
            String vehicleDescriptionOrRegistration) {
        Criteria criteria = getSession().createCriteria(
                VehicleRentalContract.class);
        // contractID filter
        if (contractID != null && contractID != 0) {
            criteria.add(Restrictions.eq("id", contractID));
        }
        // customerNameOrID filter
        if (customerNameOrID != null && customerNameOrID.length() > 0) {
            try {
                Long customerID = Long.parseLong(customerNameOrID);
                criteria.add(Restrictions.eq("customer.id", customerID));
            } catch (NumberFormatException e) {
                // assume we have a customer name
                String customerNameQuery = "%" + customerNameOrID.trim() + "%";
                criteria.createAlias("customer", "customer").add(
                        Restrictions.or(Restrictions.like("customer.firstName",
                                customerNameQuery), Restrictions.like(
                                "customer.lastName", customerNameQuery)));
            }
        }
        // date filter
        if (date != null) {
            criteria.add(Restrictions.and(
                    Restrictions.le("rentalPeriod.startDate", date),
                    Restrictions.ge("rentalPeriod.endDate", date)));
        }

        // vehicleDescriptionOrRegistration filter
        if (vehicleDescriptionOrRegistration != null
                && vehicleDescriptionOrRegistration.length() > 0) {
            String registrationQuery = "%"
                    + Vehicle
                            .normalizeRegistration(vehicleDescriptionOrRegistration)
                    + "%";
            String descriptionQuery = "%"
                    + vehicleDescriptionOrRegistration.trim() + "%";

            criteria.createAlias("vehicle", "vehicle").add(
                    Restrictions.or(Restrictions.like("vehicle.registration",
                            registrationQuery), Restrictions.like(
                            "vehicle.description", descriptionQuery)));
        }

        List<VehicleRentalContract> contracts = criteria.list();
        return contracts;
}

createAlias 调用可用于您需要在 SQL 中加入的地方。

于 2010-10-25T14:10:51.403 回答
1

两种方法:

1.. 根据您需要的过滤类型,您可以通过搜索来实现这一点,例如使用 Lucene 索引所有对象,然后使用搜索查询来执行过滤。例如建立一个查询,如:

标题:“正确的方式”和 mod_date:[20020101 TO 20030101]

见: http: //lucene.apache.org/java/2_4_0/queryparsersyntax.html


2..或使用标准...

我会使用来自休眠的新类型安全标准api:

http://relation.to/12805.lace

而不是建立一个非常大的标准的一种方法,我会尝试使用分离的标准分离出所有的逻辑 -

http://docs.jboss.org/hibernate/core/3.5/reference/en/html/querycriteria.html#querycriteria-detachedqueries

结合这两者,您将能够轻松建立标准。

另一个寻找灵感的地方是 grails 动态查找器。这本质上是您试图以静态方式实现的目标。

http://www.grails.org/doc/1.0.x/guide/single.html#5.4.1动态查找器

如果你真的想要完全分离层,你可以实现一个简单的语法。然后对其进行解析以创建相关标准。这将允许更改基础标准实现。这是否合适取决于此抽象对您的重要性。

于 2010-10-30T21:38:44.037 回答
1

即使我更喜欢使用 Criteria 而不是 HQL 和 SQL,对我来说原因将是模块化和性能,因为当项目投入生产时,我们面临的主要问题是性能,HQL 和 SQL 都无法与 Criteria 竞争性能。

添加到上面 DAO层是为了访问数据而创建的,该层应该像玻璃一样清晰,没有任何复杂的编码或业务逻辑,但是如果是标准,则必须编写一个逻辑(创建标准)才能得出一个访问对象的更好和调整的方式,所以在我看来,将这么多逻辑放在 DAO 层中并没有违反。

于 2010-10-27T13:29:06.273 回答