DATAMONGO-480 - Consider WriteResult for insert(…) and save(…) methods.
This commit is contained in:
committed by
Oliver Gierke
parent
1380c49fd0
commit
afe560ca7d
@@ -106,6 +106,7 @@ import com.mongodb.util.JSON;
|
||||
* @author Graeme Rocher
|
||||
* @author Mark Pollack
|
||||
* @author Oliver Gierke
|
||||
* @author Amol Nayak
|
||||
*/
|
||||
public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
|
||||
@@ -731,11 +732,13 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
MongoAction mongoAction = new MongoAction(writeConcern, MongoActionOperation.INSERT, collectionName,
|
||||
entityClass, dbDoc, null);
|
||||
WriteConcern writeConcernToUse = prepareWriteConcern(mongoAction);
|
||||
WriteResult wr;
|
||||
if (writeConcernToUse == null) {
|
||||
collection.insert(dbDoc);
|
||||
wr = collection.insert(dbDoc);
|
||||
} else {
|
||||
collection.insert(dbDoc, writeConcernToUse);
|
||||
wr = collection.insert(dbDoc, writeConcernToUse);
|
||||
}
|
||||
handleAnyWriteResultErrors(wr, dbDoc, "insert");
|
||||
return dbDoc.get(ID);
|
||||
}
|
||||
});
|
||||
@@ -754,11 +757,13 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
MongoAction mongoAction = new MongoAction(writeConcern, MongoActionOperation.INSERT_LIST, collectionName, null,
|
||||
null, null);
|
||||
WriteConcern writeConcernToUse = prepareWriteConcern(mongoAction);
|
||||
WriteResult wr;
|
||||
if (writeConcernToUse == null) {
|
||||
collection.insert(dbDocList);
|
||||
wr = collection.insert(dbDocList);
|
||||
} else {
|
||||
collection.insert(dbDocList.toArray((DBObject[]) new BasicDBObject[dbDocList.size()]), writeConcernToUse);
|
||||
wr = collection.insert(dbDocList.toArray((DBObject[]) new BasicDBObject[dbDocList.size()]), writeConcernToUse);
|
||||
}
|
||||
handleAnyWriteResultErrors(wr, null, "insert_list");
|
||||
return null;
|
||||
}
|
||||
});
|
||||
@@ -785,11 +790,13 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
MongoAction mongoAction = new MongoAction(writeConcern, MongoActionOperation.SAVE, collectionName, entityClass,
|
||||
dbDoc, null);
|
||||
WriteConcern writeConcernToUse = prepareWriteConcern(mongoAction);
|
||||
WriteResult wr;
|
||||
if (writeConcernToUse == null) {
|
||||
collection.save(dbDoc);
|
||||
wr = collection.save(dbDoc);
|
||||
} else {
|
||||
collection.save(dbDoc, writeConcernToUse);
|
||||
wr = collection.save(dbDoc, writeConcernToUse);
|
||||
}
|
||||
handleAnyWriteResultErrors(wr, dbDoc, "save");
|
||||
return dbDoc.get(ID);
|
||||
}
|
||||
});
|
||||
@@ -874,7 +881,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
|
||||
/**
|
||||
* Returns a {@link Query} for the given entity by its id.
|
||||
*
|
||||
*
|
||||
* @param object must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@@ -1165,7 +1172,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
|
||||
/**
|
||||
* Create the specified collection using the provided options
|
||||
*
|
||||
*
|
||||
* @param collectionName
|
||||
* @param collectionOptions
|
||||
* @return the collection that was created
|
||||
@@ -1187,7 +1194,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
* Map the results of an ad-hoc query on the default MongoDB collection to an object using the template's converter
|
||||
* <p/>
|
||||
* The query document is specified as a standard DBObject and so is the fields specification.
|
||||
*
|
||||
*
|
||||
* @param collectionName name of the collection to retrieve the objects from
|
||||
* @param query the query document that specifies the criteria used to find a record
|
||||
* @param fields the document that specifies the fields to be returned
|
||||
@@ -1212,7 +1219,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
* The query document is specified as a standard DBObject and so is the fields specification.
|
||||
* <p/>
|
||||
* Can be overridden by subclasses.
|
||||
*
|
||||
*
|
||||
* @param collectionName name of the collection to retrieve the objects from
|
||||
* @param query the query document that specifies the criteria used to find a record
|
||||
* @param fields the document that specifies the fields to be returned
|
||||
@@ -1242,7 +1249,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
* Map the results of an ad-hoc query on the default MongoDB collection to a List using the template's converter.
|
||||
* <p/>
|
||||
* The query document is specified as a standard DBObject and so is the fields specification.
|
||||
*
|
||||
*
|
||||
* @param collectionName name of the collection to retrieve the objects from
|
||||
* @param query the query document that specifies the criteria used to find a record
|
||||
* @param fields the document that specifies the fields to be returned
|
||||
@@ -1281,7 +1288,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
* The first document that matches the query is returned and also removed from the collection in the database.
|
||||
* <p/>
|
||||
* The query document is specified as a standard DBObject and so is the fields specification.
|
||||
*
|
||||
*
|
||||
* @param collectionName name of the collection to retrieve the objects from
|
||||
* @param query the query document that specifies the criteria used to find a record
|
||||
* @param entityClass the parameterized type of the returned list.
|
||||
@@ -1328,7 +1335,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
|
||||
/**
|
||||
* Populates the id property of the saved object, if it's not set already.
|
||||
*
|
||||
*
|
||||
* @param savedObject
|
||||
* @param id
|
||||
*/
|
||||
@@ -1381,7 +1388,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
* <li>Execute the given {@link ConnectionCallback} for a {@link DBObject}.</li>
|
||||
* <li>Apply the given {@link DbObjectCallback} to each of the {@link DBObject}s to obtain the result.</li>
|
||||
* <ol>
|
||||
*
|
||||
*
|
||||
* @param <T>
|
||||
* @param collectionCallback the callback to retrieve the {@link DBObject} with
|
||||
* @param objectCallback the {@link DbObjectCallback} to transform {@link DBObject}s into the actual domain type
|
||||
@@ -1504,9 +1511,16 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
String error = wr.getError();
|
||||
|
||||
if (error != null) {
|
||||
|
||||
String message = String.format("Execution of %s%s failed: %s", operation, query == null ? "" : "' using '"
|
||||
+ query.toString() + "' query", error);
|
||||
String message;
|
||||
if (operation.equals("insert") || operation.equals("save")) {
|
||||
// assuming the insert operations will begin with insert string
|
||||
message = String.format("Insert/Save for %s failed: %s", query, error);
|
||||
} else if (operation.equals("insert_list")) {
|
||||
message = String.format("Insert list failed: %s", error);
|
||||
} else {
|
||||
message = String.format("Execution of %s%s failed: %s", operation,
|
||||
query == null ? "" : "' using '" + query.toString() + "' query", error);
|
||||
}
|
||||
|
||||
if (WriteResultChecking.EXCEPTION == this.writeResultChecking) {
|
||||
throw new DataIntegrityViolationException(message);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011 the original author or authors.
|
||||
* Copyright 2011-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -37,9 +37,9 @@ import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.PersistenceConstructor;
|
||||
import org.springframework.data.mongodb.InvalidMongoDbApiUsageException;
|
||||
@@ -73,6 +73,7 @@ import com.mongodb.WriteResult;
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Risberg
|
||||
* @author Amol Nayak
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration("classpath:infrastructure.xml")
|
||||
@@ -163,6 +164,112 @@ public class MongoTemplateTests {
|
||||
mongoTemplate.updateFirst(q, u, Person.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-480
|
||||
*/
|
||||
@Test
|
||||
public void throwsExceptionForDuplicateIds() {
|
||||
|
||||
MongoTemplate template = new MongoTemplate(factory);
|
||||
template.setWriteResultChecking(WriteResultChecking.EXCEPTION);
|
||||
|
||||
Person person = new Person(new ObjectId(), "Amol");
|
||||
person.setAge(28);
|
||||
|
||||
template.insert(person);
|
||||
|
||||
try {
|
||||
template.insert(person);
|
||||
fail("Expected DataIntegrityViolationException!");
|
||||
} catch (DataIntegrityViolationException e) {
|
||||
assertThat(e.getMessage(), containsString("E11000 duplicate key error index: database.person.$_id_ dup key:"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-480
|
||||
*/
|
||||
@Test
|
||||
public void throwsExceptionForUpdateWithInvalidPushOperator() {
|
||||
|
||||
MongoTemplate template = new MongoTemplate(factory);
|
||||
template.setWriteResultChecking(WriteResultChecking.EXCEPTION);
|
||||
|
||||
ObjectId id = new ObjectId();
|
||||
Person person = new Person(id, "Amol");
|
||||
person.setAge(28);
|
||||
|
||||
template.insert(person);
|
||||
|
||||
try {
|
||||
|
||||
Query query = new Query(Criteria.where("firstName").is("Amol"));
|
||||
Update upd = new Update().push("age", 29);
|
||||
template.updateFirst(query, upd, Person.class);
|
||||
fail("Expected DataIntegrityViolationException!");
|
||||
|
||||
} catch (DataIntegrityViolationException e) {
|
||||
|
||||
assertThat(e.getMessage(),
|
||||
is("Execution of update with '{ \"$push\" : { \"age\" : 29}}'' using '{ \"firstName\" : \"Amol\"}' "
|
||||
+ "query failed: Cannot apply $push/$pushAll modifier to non-array"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-480
|
||||
*/
|
||||
@Test
|
||||
public void throwsExceptionForIndexViolationIfConfigured() {
|
||||
|
||||
MongoTemplate template = new MongoTemplate(factory);
|
||||
template.setWriteResultChecking(WriteResultChecking.EXCEPTION);
|
||||
template.indexOps(Person.class).ensureIndex(new Index().on("firstName", Order.DESCENDING).unique());
|
||||
|
||||
Person person = new Person(new ObjectId(), "Amol");
|
||||
person.setAge(28);
|
||||
|
||||
template.save(person);
|
||||
|
||||
person = new Person(new ObjectId(), "Amol");
|
||||
person.setAge(28);
|
||||
|
||||
try {
|
||||
template.save(person);
|
||||
fail("Expected DataIntegrityViolationException!");
|
||||
} catch (DataIntegrityViolationException e) {
|
||||
assertThat(e.getMessage(),
|
||||
containsString("E11000 duplicate key error index: database.person.$firstName_-1 dup key:"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-480
|
||||
*/
|
||||
@Test
|
||||
public void rejectsDuplicateIdInInsertAll() {
|
||||
|
||||
MongoTemplate template = new MongoTemplate(factory);
|
||||
template.setWriteResultChecking(WriteResultChecking.EXCEPTION);
|
||||
|
||||
ObjectId id = new ObjectId();
|
||||
Person person = new Person(id, "Amol");
|
||||
person.setAge(28);
|
||||
|
||||
List<Person> records = new ArrayList<Person>();
|
||||
records.add(person);
|
||||
records.add(person);
|
||||
|
||||
try {
|
||||
template.insertAll(records);
|
||||
fail("Expected DataIntegrityViolationException!");
|
||||
} catch (DataIntegrityViolationException e) {
|
||||
assertThat(
|
||||
e.getMessage(),
|
||||
startsWith("Insert list failed: E11000 duplicate key error index: database.person.$_id_ dup key: { : ObjectId"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnsureIndex() throws Exception {
|
||||
|
||||
@@ -193,7 +300,7 @@ public class MongoTemplateTests {
|
||||
assertThat(dropDupes, is(true));
|
||||
|
||||
List<IndexInfo> indexInfoList = template.indexOps(Person.class).getIndexInfo();
|
||||
System.out.println(indexInfoList);
|
||||
|
||||
assertThat(indexInfoList.size(), is(2));
|
||||
IndexInfo ii = indexInfoList.get(1);
|
||||
assertThat(ii.isUnique(), is(true));
|
||||
@@ -939,7 +1046,7 @@ public class MongoTemplateTests {
|
||||
DBRef first = new DBRef(factory.getDb(), "foo", new ObjectId());
|
||||
DBRef second = new DBRef(factory.getDb(), "bar", new ObjectId());
|
||||
|
||||
template.updateFirst(null, Update.update("dbRefs", Arrays.asList(first, second)), ClassWithDBRefs.class);
|
||||
template.updateFirst(null, update("dbRefs", Arrays.asList(first, second)), ClassWithDBRefs.class);
|
||||
}
|
||||
|
||||
class ClassWithDBRefs {
|
||||
@@ -1102,7 +1209,7 @@ public class MongoTemplateTests {
|
||||
template.save(second);
|
||||
|
||||
Query query = query(where("field").not().regex("Matthews"));
|
||||
System.out.println(query.getQueryObject());
|
||||
|
||||
List<Sample> result = template.find(query, Sample.class);
|
||||
assertThat(result.size(), is(1));
|
||||
assertThat(result.get(0).field, is("Beauford"));
|
||||
|
||||
Reference in New Issue
Block a user