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");


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM