【问题标题】:Want to modify Hibernate criteria using entity想要使用实体修改 Hibernate 标准
【发布时间】:2014-08-20 16:17:59
【问题描述】:

在我的示例中,我只使用我的实体对象“合同”创建了一个 Hibernate 标准。

     @Transactional
    public static List<Contract> findAllContractsPerContract(Contract contract) {
        EntityManager e = entityManager().getEntityManagerFactory().createEntityManager();
        Session session = e.unwrap(Session.class);
        Example contractExample = Example.create(contract).excludeProperty("fromDate").excludeProperty("endDate");;
        Criteria c = session.createCriteria(Contract.class).add(contractExample);
        // here some restriction can be done. (in a dynamic way like equlas/greater/less...)
        List<Contract> list = c.list();
        return list;
    }

合约对象有很多参数。在这种情况下,合约的所有参数都通过 equals 搜索。所以,如果参数匹配,我会得到正确的结果。

但现在我想为合约对象的一些参数添加一些标准。例如两个参数是:“fromDate”和“endDate”。可以修改现有标准,例如 >= fromDate 和 (或介于两者之间)。标准也应该是动态的。

我知道我可以在这一行的末尾添加一些标准:

Criteria c = session.createCriteria(Contract.class).add(contractExample);

但这只是对现有查询的补充。 是否有解决方案或其他技术方法来解决问题?

感谢您的意见。

更新 1

没有操作数的请求:

allRequestParams={"v00Datvon":"09-07-2014","v00Datbis":"09-07-2014","v00Saicode":{"saiCode":"SO02"}}

带有操作数的请求示例

allRequestParams={"v00Datvon":"09-07-2014","operand":"less","v00Datbis":"09-07-2014","operand":"greater","v00Saicode":{"saiCode":"SO02","operand":"equals"}}

在控制器中,我得到这样的 JSON 字符串:

    @RequestMapping(value = "/", method = RequestMethod.GET, headers = "Accept=text/plain")
    public ResponseEntity<String> getVertagFromSearch(@RequestParam String allRequestParams, ModelMap model) throws JsonProcessingException{
//do stuff
}

更新 2

另一个大问题是合约的子域对象。 v00Saicode 依赖于合约。 日期也有同样的问题。如果没有将 JSON 字符串解析为合同对象,我会丢失 Calender 类的转换。 我真的储存了我应该如何在控制器中做出反应。有没有人有解决办法。

解决方案

这是我以动态方式完成所有部分的方式。

请求为操作员提供了额外的部分。

控制器收到这样的字符串:

@RequestMapping(value = "/", method = RequestMethod.GET, headers = "Accept=text/plain")
public ResponseEntity<String> getVertagFromSearch(@RequestParam String allRequestParams,@RequestParam String operators, ModelMap model) throws JsonParseException, JsonMappingException, IOException, IntrospectionException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    HashMap<String, String> operatorsMap = new ObjectMapper().readValue(operators, HashMap.class);
    Contract contract = Contract.fromJsonToContract(allRequestParams);
    List<Contract> list = Contract.findAllContractsPerContract(contract, operatorsMap);
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Type", "application/json");
    return new ResponseEntity<String>(Contract.toJsonArray(list),headers,HttpStatus.OK);
}

DAO 和对助手类的调用

      public static List<Contract> findAllContractsPerContract(Contract contract, Map<String, String> operatorMap) throws IntrospectionException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    EntityManager e = entityManager().getEntityManagerFactory().createEntityManager();
    Session session = e.unwrap(Session.class);
    Criteria criteria = session.createCriteria(Contract.class);
    criteria = CriteriaBuilder.buildCriteria(contract, criteria, operatorMap);
    List<Contract> list = criteria.list();
    return list;
}

@Jeff 答案的 Criteria Builder 助手类和代码:

public static Criteria buildCriteria(Object object, Criteria criteria, Map<String,String> operatorMap) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, IntrospectionException{
     BeanInfo vertagInfo = Introspector.getBeanInfo(Contract.class);
        for(PropertyDescriptor propertyDescriptor : vertagInfo.getPropertyDescriptors()){
            String propertyString = propertyDescriptor.getName();
            Object value = propertyDescriptor.getReadMethod().invoke(object);
            if(propertyString.equals("class")||value==null){
                continue;
            }
            String operator = operatorMap.get(propertyString);
            if(operator==null){
                operator="EQ";
            }
            criteria.add(Comparison.valueOf(operator).convert(propertyString, value));
        }
    return criteria;
}

【问题讨论】:

  • 对于这个问题还有其他帮助吗?
  • 我不明白你在控制器层的症结所在。您使用什么库将 JSON 解析为 Java 对象?您不必满足于合同对象或数据字符串;您应该能够创建 JSON 反序列化到的新 DTO(ContractCriteria 或其他东西),并且它可以具有内部日历成员。
  • @Jeff 更新后的答案唤醒了我。

标签: java hibernate jpa entitymanager hibernate-criteria


【解决方案1】:

从您的 Contract 实例中获取起始日期和结束日期的值,然后在该实例中将它们设置为 null。 Example.create(contract) 不会为那些 null 字段添加默认的 eq 限制,然后您可以按照 @Pracede 的代码进行 ge 和 le 限制。

您也可以在 Example 实例上调用 excludeProperty() 来手动添加日期字段。这可能是更优雅的方式。

更新

如果您需要它来根据用户输入动态构建标准,那么通过示例查询可能不是可行的方法。创建一个可以处理您关心的所有比较类型的枚举,并为每种类型返回适当的 Criterion 比较:

public enum Comparison {
    EQ {
        @Override
        public Criterion convert(String propertyName, Object propertyValue) {
            return Restrictions.eq(propertyName, propertyValue);
        }
    },
    LE {
        @Override
        public Criterion convert(String propertyName, Object propertyValue) {
            return Restrictions.le(propertyName, propertyValue);
        }
    },
    LIKE {
        @Override
        public Criterion convert(String propertyName, Object propertyValue) {
            return Restrictions.like(propertyName, propertyValue);
        }
    };

    public abstract Criterion convert(String propertyName, Object propertyValue);
}

然后,当您在控制器中处理 JSON 输入时,为每个比较获取正确的枚举类型,并让它为您提供所需的限制:

Criteria c = session.createCriteria(Contract.class);
for each name, value, comparator in JSON data*
    c.add(Comparison.valueOf(comparator).convert(name, value)

*注意:我并不是建议你将 DAO 代码移到控制器中;与其将 Contract 实例传递给您的 DAO,不如传递一个表示来自 JSON 输入的数据的对象数组。

【讨论】:

  • 使用excludeProperty() 方法对我有用。您是否有解决方案以动态方式创建 Hibernate 限制。因为我现在不知道,控制器会受到哪些限制。 (ge/le/eq) 谢谢。
  • 控制器如何指示应该发生除相等比较之外的事情?
  • 应该来自UI部分。应该有一个以 JSON 格式发送参数的 ajax 调用。
  • 更新答案以包含动态限制
  • 这是一个非常好的解决方案。您对我需要如何发送 json 请求有任何建议吗?并在控制器中使用字符串。也许是一个有一个键和两个值的地图?在更新的问题中查看详细信息
【解决方案2】:

你试过了吗:

 if(fromDate!= null && endDate=null) {
                criteria.add(Expression.ge("date", fromDate));

                criteria.add(Expression.le("date", endDate));
            }

您必须将下一个条件添加到当前条件。

【讨论】:

  • 我已经尝试过了:c.add(Restrictions.ge("fromDate", contract.getFromDate())) 但后来我得到了一个空列表。无需将实体添加到条件中,它就可以工作。
  • 检查数据库日期格式是否与Criteria提供的一致。
  • 是的,它是一样的。我想我需要编写另一种方法来动态创建限制。 (CriteriaBuilder) 还是有其他解决方案。如果有人需要更多输入,请告诉我。谢谢
猜你喜欢
  • 2020-06-14
  • 1970-01-01
  • 2013-05-11
  • 1970-01-01
  • 2018-12-14
  • 1970-01-01
  • 1970-01-01
  • 2019-08-20
  • 1970-01-01
相关资源
最近更新 更多