Запретить Spring Data для Mongo преобразовывать идентификаторы в ObjectId

Я использую Spring Data для Mongo в существующей базе данных. Предыдущее приложение использовало простые строки для идентификаторов вместо ObjectId.

Моя проблема в том, что Spring Data настаивает на преобразовании строк в ObjectId, что приводит к сбою всех запросов по идентификатору.

Например, когда я делаю repository.findOne(''), выполняется запрос { "_id" : { "$oid" : "50cf9f34458cf91108ceb2b4"}}, тогда как он должен быть { "_id" : "50cf9f34458cf91108ceb2b4" }

Есть ли способ избежать Spring Data для преобразования идентификаторов строк в ObjectId?

Спасибо!

Диего


person dgaviola    schedule 15.01.2013    source источник
comment
Не могли бы вы предоставить больше кода? SD MongoDB не принудительно переводит все String в ObjectId. Если у вас есть String значения для идентификаторов, которые можно преобразовать в ObjectId, поскольку MongoDB оптимизирован для использования с ними. Помимо этого, выполнение запроса также выполняет такое же сопоставление при выполнении запросов, поэтому вы не должны видеть поведение, которое вы видите в первую очередь. Не могли бы вы добавить класс домена, объявление репозитория (ваш findOne('') не имеет особого смысла, как и клиентский код, пытающийся сохранить и прочитать объект?   -  person Oliver Drotbohm    schedule 15.01.2013
comment
@OliverGierke У меня такая же проблема, когда некоторые из моих объектов имеют идентификаторы, которые систематически назначаются путем преобразования ObjectId в строку. Да, в этом случае нам нужно использовать идентификаторы как строку. Следовательно, логика Если у вас есть строковые значения для идентификаторов, которые могут быть преобразованы в ObjectId, для нас не работает.   -  person Stackee007    schedule 07.02.2014
comment
@OliverGierke У меня тоже такая проблема. А пока есть решение? Спасибо   -  person Daniel Sass    schedule 11.09.2017
comment
@OliverGierke Можно ли добавить еще одну аннотацию, например NoDefaultConversion, к полям Id, чтобы предотвратить преобразование по умолчанию из String в ObjectId? На данный момент каждое число длиной 24 рассматривается как действительный идентификатор объекта.   -  person Daniel Sass    schedule 09.10.2017
comment
Созданная проблема: jira.spring.io/browse/DATAMONGO-1798   -  person Daniel Sass    schedule 11.10.2017


Ответы (4)


Я наконец нашел решение для этого. Возможно не лучший вариант, но работает.

Я удалил преобразователь с String на ObjectId, который MongoTemplate использует через QueryMapper. Таким образом, я создал следующий конвертер Mongo:

public class CustomMongoConverter extends MappingMongoConverter {
    public CustomMongoConverter(MongoDbFactory mongoDbFactory, MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext) {
        super(mongoDbFactory, mappingContext);
        conversionService.addConverter(new Converter<String, ObjectId>() {
            @Override
            public ObjectId convert(String source) {
                throw new RuntimeException();
            }
        });
    }
}

А затем я передал эту реализацию преобразователя в MongoTemplate:

<bean id="mongoConverter" class="com.abcompany.model.repositories.utils.CustomMongoConverter">
    <constructor-arg ref="mongoDbFactory"/>
    <constructor-arg>
        <bean class="org.springframework.data.mongodb.core.mapping.MongoMappingContext"/>
    </constructor-arg>
</bean>

<bean class="org.springframework.data.mongodb.core.MongoTemplate" id="mongoTemplate">
    <constructor-arg ref="mongoDbFactory"/>
    <constructor-arg ref="mongoConverter"/>
</bean>

Таким образом, при попытке преобразовать из String в ObjectId он выдает исключение, но не делает этого. Обратите внимание, что вы, вероятно, можете просто удалить конвертер из conversionService.

person dgaviola    schedule 15.01.2013
comment
Ваше решение работает, если вы никогда не собираетесь использовать ObjectId Mongo. Если вы планируете использовать ObjectId, решение не срабатывает. - person Stackee007; 07.02.2014
comment
Какой тип объекта conversionService? - person digz6666; 14.10.2015
comment
не могли бы вы предложить, используя полную аннотацию. - person so_what; 13.08.2019

Я столкнулся с той же проблемой, и мое решение было таким, как показано ниже:

  @Bean
  public MappingMongoConverter mappingMongoConverter(MongoDbFactory factory, MongoMappingContext context, CustomConversions conversions) {
    MappingMongoConverter converter = new MappingMongoConverter(new DefaultDbRefResolver(factory), context) {
      @Override
      public void afterPropertiesSet() {
        conversions.registerConvertersIn(conversionService);
      }
    };
    converter.setCustomConversions(conversions);
    return converter;
  }

Идея состоит в том, чтобы предотвратить регистрацию преобразователей по умолчанию.

person Sergii Motynga    schedule 06.06.2017
comment
Это предотвратило регистрацию преобразователя по умолчанию (в AbstractMongoConverter), но Spring использовал другой преобразователь и сопоставил его с ObjectId, о котором я не знаю, поэтому он не работает для меня. - person ZZ 5; 10.10.2017

теперь достаточно просто переопределить метод convertId в MappingMongoConverter.

по умолчанию здесь https://github.com/spring-projects/spring-data-mongodb/blob/master/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConverter.java#L128. Как видим, convertService не так уж и полезен.

это часть моей конфигурации (мне вообще не нужен ObjectId из строки в моих коллекциях):

@Configuration
public class MongoCommonConfig extends AbstractMongoClientConfiguration {
    ...
    @Bean
    @Primary
    public MongoTemplate mongoTemplate(MongoDbFactory dbFactory, 
        MappingMongoConverter mappingMongoConverter) {
        return new MongoTemplate(dbFactory, mappingMongoConverter);
    }

    @Bean
    @Primary
    @Override
    public @NotNull MappingMongoConverter mappingMongoConverter() throws Exception {
        DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory());
        MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, mongoMappingContext()) {
            @Override
            public Object convertId(Object id, @NotNull Class<?> targetType) {
                return id;
            }
        };
        converter.setCustomConversions(customConversions());
        converter.setCodecRegistryProvider(mongoDbFactory());

        return converter;
    }
    ...
}
person serhii    schedule 10.07.2020

Я нашел более простой подход к тому же самому serhii, где вы только переопределяете метод convertId в классе MobileMappingMongoConverter, вы ' Я найду его в этом сообщении.

person Mostafa Omar    schedule 30.11.2020