zoukankan      html  css  js  c++  java
  • InvalidMongoDbApiUsageException之重复的字段条件

    1. 异常

    org.springframework.data.mongodb.InvalidMongoDbApiUsageException: Due to limitations of the com.mongodb.BasicDocument, you can't add a second 'xxx' criteria. Query already contains...

    2. 出现场景

    • 显性地使用了重复的字段(key)进行查询:
    Query query = new Query();
    query.addCriteria(Criteria.where("name").is(name)); 
    query.addCriteria(Criteria.where("name").is(name)); // 与上一行重复使用了字段:name
    UserVO user = mongoTemplate.findOne(query, UserVO.class, "QWS_TEST_TABLE");
    

    抛出异常:...you can't add a second 'name' criteria.

    • 隐性地使用了重复的字段(key)进行查询
    Query query = new Query();
    query.addCriteria(new Criteria().andOperator(Criteria.where("name").is(name)));
    query.addCriteria(new Criteria().andOperator(Criteria.where("age").is(age))); // 与上一行重复使用了字段:null
    UserVO user = mongoTemplate.findOne(query, UserVO.class, "QWS_TEST_TABLE");
    

    抛出异常:...you can't add a second 'null' criteria,为什么是null呢?请往下看。

    3. 源码分析

    首先查看addCriteria()方法,第一找到抛异常的源头:

    public Query addCriteria(CriteriaDefinition criteriaDefinition) {
        // 查询当前字段是否存在设置了操作条件
        CriteriaDefinition existing = (CriteriaDefinition)this.criteria.get(criteriaDefinition.getKey());
        String key = criteriaDefinition.getKey();
        if (existing == null) { // 如果不存在,那么添加当前字段的操作条件
            this.criteria.put(key, criteriaDefinition);
            return this;
        } else { // 如果已经存在,那么抛出异常
            throw new InvalidMongoDbApiUsageException(String.format("Due to limitations of the com.mongodb.BasicDocument, you can't add a second '%s' criteria. Query already contains '%s'", key, SerializationUtils.serializeToJsonSafely(existing.getCriteriaObject())));
        }
    }
    

    通过源码知道:如果某个字段(key)已经存在了条件,那么第二次去重复设置条件时,会抛出异常。回到上述问题,为什么key为null?

    通过查看where()方法和Criteria的构造函数源码:

    // where方法
    public static Criteria where(String key) {
        return new Criteria(key);
    }
    
    // 无参构造函数
    public Criteria() {
        this.isValue = NOT_SET;
        this.criteriaChain = new ArrayList();
    }
    
    // 有参构造函数
    public Criteria(String key) {
        this.isValue = NOT_SET;
        this.criteriaChain = new ArrayList();
        this.criteriaChain.add(this);
        this.key = key;
    }
    

    发现Criteria.where("name").is(name)最终调用了构造函数,设置了key等于“name”;而new Criteria().andOperator(Criteria.where("name").is(name))中的new Criteria()调用了无参的构造函数,因此key为null。

    4. 如何避免出现InvalidMongoDbApiUsageException

    根源在于query.addCriteria(Criteria c)每次调用都会设置一个类似key=value的条件,且不能重复地使用重复的字段(key)条件,所以对于比较复杂的业务,我们只要保证addCriteria()被调用一次即可。

    直接上代码:

    Query query = new Query();
    Criteria c1 = Criteria.where("name").is("张三");
    Criteria c2 = Criteria.where("name").is("李四");
    Criteria c3 = new Criteria().andOperator(Criteria.where("name").is("王五"));
    Criteria c4 = new Criteria().andOperator(Criteria.where("name").is("赵六"));
    query.addCriteria(new Criteria().andOperator(c1, c2, c3, c4)); // 保证只调用一次addCriteria()
    UserVO user = mongoTemplate.findOne(query, UserVO.class, "QWS_TEST_TABLE");
    
  • 相关阅读:
    EF中的EntityState几个状态的说明
    sql server 更新表,每天的数据分固定批次设置批次号sql
    bootstrap Validators
    马老师 生产环境mysql主从复制、架构优化方案
    PHP在微博优化中的“大显身手”
    将form表单转化为json数据
    免费资源库收集
    奇怪的php问题
    PHP 大数自动转换为科学计数法
    access database in a helper function ?
  • 原文地址:https://www.cnblogs.com/qinvis/p/12892467.html
Copyright © 2011-2022 走看看