MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Récupération de la clé MongoDB spécifique à partir de DuplicateKeyException qui a été réellement dupliquée (Java/Spring)

Pas vraiment, car le pilote Java Mongo expose déjà la dernière erreur sous forme de chaîne construite :

writeResult.getLastError().get("err") renvoie quelque chose comme :

insertDocument :: caused by :: 11000 E11000 duplicate key error index: test.person.$username dup key: { : "joe" }

C'est également vrai pour le shell et chaque pilote, j'imagine.

Une solution raisonnable, je pense, consiste à analyser cette exception de clé en double à l'aide d'une exception personnalisée :

public class DetailedDuplicateKeyException extends DuplicateKeyException {
    public DetailedDuplicateKeyException(String msg) {
        // Instead of just calling super parse the message here.
        super(msg);
    }
}

... un traducteur d'exception personnalisé :

public class DetailedDuplicateKeyExceptionTransaltor extends MongoExceptionTranslator {

    @Override
    public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
        if (ex instanceof MongoException.DuplicateKey) {
            return new DetailedDuplicateKeyException(ex.getMessage());
        }
        return super.translateExceptionIfPossible(ex);
    }
}

... et définir correctement la configuration de Spring :

@Bean
public MongoFactoryBean mongo() {
    MongoFactoryBean mongo = new MongoFactoryBean();
    mongo.setExceptionTranslator(new DetailedDuplicateKeyExceptionTransaltor());
    mongo.setHost("localhost");
    return mongo;
}

MODIFIER

Après avoir inspecté MongoTemplate code (1.4.1.RELEASE), il semble qu'en interne un SimpleMongoDbFactory est utilisé pour récupérer un MongoExceptionTranslator par défaut , donc celui créé avec MongoFactoryBean est ombragé. Avait manqué cette partie.

La solution consiste à remplacer SimpleMongoDbFactory (oubliez MongoFactoryBean , ça ne sert à rien dans ce contexte):

public class MySimpleMongoDbFactory extends SimpleMongoDbFactory {

    PersistenceExceptionTranslator translator = new       
            DetailedDuplicateKeyExceptionTransaltor();

    public MySimpleMongoDbFactory(Mongo mongo, String databaseName) {
        super(mongo, databaseName);
    }

    @Override
    public PersistenceExceptionTranslator getExceptionTranslator() {
        return translator;
    }
}

Vous pouvez maintenant créer un modèle à l'aide de la MongoDbFactory personnalisée :

template = new MongoTemplate (new MySimpleMongoDbFactory(new MongoClient(), "test"));

J'avais essayé, et celui-ci fonctionne pour moi.