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");
    
  • 相关阅读:
    hdu 2019 数列有序!
    hdu 2023 求平均成绩
    HDU 5805 NanoApe Loves Sequence (思维题) BestCoder Round #86 1002
    51nod 1264 线段相交
    Gym 100801A Alex Origami Squares (求正方形边长)
    HDU 5512 Pagodas (gcd)
    HDU 5510 Bazinga (字符串匹配)
    UVALive 7269 Snake Carpet (构造)
    UVALive 7270 Osu! Master (阅读理解题)
    UVALive 7267 Mysterious Antiques in Sackler Museum (判断长方形)
  • 原文地址:https://www.cnblogs.com/qinvis/p/12892467.html
Copyright © 2011-2022 走看看