Вопрос

По умолчанию Картирование Монгоконвертер Добавляет клавишу пользовательского типа ("_class") в каждый объект в базе данных. Итак, если я создаю человека:

package my.dto;
public class Person {
    String name;
    public Person(String name) {
        this.name = name; 
    }
}

и сохранить его в БД:

MongoOperations ops = new MongoTemplate(new Mongo(), "users");
ops.insert(new Person("Joe"));

Полученным объектом в монго будет:

{ "_id" : ObjectId("4e2ca049744e664eba9d1e11"), "_class" : "my.dto.Person", "name" : "Joe" }

Вопросы:

  1. Каковы последствия перемещения класса человека в другое пространство имен?

  2. Возможно ли не загрязнять объект с помощью ключа "_class"; Не написав уникальный конвертер только для класса человека?

Это было полезно?

Решение

Итак, вот история: мы по умолчанию добавляем тип как какой -то намек на то, какой класс на самом деле экземплятся. Как вам нужно вписать в тип, чтобы прочитать документ в VIA MongoTemplate В любом случае есть два возможных варианта:

  1. Вы передаете тип фактического хранимого типа можно назначить. В этом случае мы рассмотрим сохраненный тип, используйте его для создания объектов. Классический пример здесь выполняет полиморфные запросы. Предположим, у вас есть абстрактный класс Contact и ваш Person. Анкет Тогда вы можете запросить ContactS и мы по существу иметь Определите тип для экземпляра.
  2. Если вы - с другой стороны - пройдите совершенно другой тип, мы просто засорим этот тип, а не в тот, который на самом деле хранится в документе. Это охватит ваш вопрос, что произойдет, если вы переместите тип.

Вы можете быть заинтересованы в просмотре этот билет который охватывает какую -то стратегию отображения плановых типов, чтобы превратить информацию типа в фактический тип. Это может служить простой целях сохранения пространства, так как вы, возможно, захотите уменьшить давно квалифицированное название класса в хэш из нескольких букв. Это также позволит более сложные сценарии миграции, где вы можете найти совершенно произвольные ключи типа, созданные другим клиентом данных, и связывать их с типами Java.

Другие советы

Вот моя аннотация, и это работает.

@Configuration
public class AppMongoConfig {

    public @Bean
    MongoDbFactory mongoDbFactory() throws Exception {
        return new SimpleMongoDbFactory(new Mongo(), "databasename");
    }

    public @Bean
    MongoTemplate mongoTemplate() throws Exception {

        //remove _class
        MappingMongoConverter converter = new MappingMongoConverter(mongoDbFactory(), new MongoMappingContext());
        converter.setTypeMapper(new DefaultMongoTypeMapper(null));

        MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory(), converter);

        return mongoTemplate;

    }

}
<mongo:mongo host="hostname" port="27017">
<mongo:options
...options...
</mongo:mongo>
<mongo:db-factory dbname="databasename" username="user" password="pass"                     mongo-ref="mongo"/>
<bean id="mongoTypeMapper"     class="org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper">
<constructor-arg name="typeKey"><null/></constructor-arg>
</bean>
<bean id="mongoMappingContext"      class="org.springframework.data.mongodb.core.mapping.MongoMappingContext" />
<bean id="mongoConverter"     class="org.springframework.data.mongodb.core.convert.MappingMongoConverter">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory" />
<constructor-arg name="mappingContext" ref="mongoMappingContext" />
<property name="typeMapper" ref="mongoTypeMapper"></property>
</bean>
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
<constructor-arg name="mongoConverter" ref="mongoConverter" />
<property name="writeResultChecking" value="EXCEPTION" /> 
</bean>

Если вы хотите отключить _class атрибут по умолчанию, но сохраните полиморфизм для указанных классов, вы можете объяснить тип _class (необязательно) Поле путем настройки:

@Bean
public MongoTemplate mongoTemplate() throws Exception {
    Map<Class<?>, String> typeMapperMap = new HashMap<>();
    typeMapperMap.put(com.acme.domain.SomeDocument.class, "role");

    TypeInformationMapper typeMapper1 = new ConfigurableTypeInformationMapper(typeMapperMap);

    MongoTypeMapper typeMapper = new DefaultMongoTypeMapper(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY, Arrays.asList(typeMapper1));
    MappingMongoConverter converter = new MappingMongoConverter(mongoDbFactory(), new MongoMappingContext());
    converter.setTypeMapper(typeMapper);

    MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory(), converter);
    return mongoTemplate;
}

Это сохранит _class Поле (или как вы хотите назвать в Construtor) только для указанных объектов.

Вы также можете написать собственный TypeInformationMapper Например, на основе аннотаций. Если вы аннотируете свой документ @DocumentType("aliasName") Вы будете сохранять полиморфизм, сохранив псевдоним класса.

Я кратко объяснил это в своем блоге, но вот какой -то кусочек быстрого кода:https://gist.github.com/athlan/6497C74CC515131E1336

В то время как ответ Mkyong все еще работает, я хотел бы добавить свою версию решения, так как мало битов устарело и может быть на грани очистки.

Например : MappingMongoConverter(mongoDbFactory(), new MongoMappingContext()) устарел в пользу new MappingMongoConverter(dbRefResolver, new MongoMappingContext()); а также SimpleMongoDbFactory(new Mongo(), "databasename"); в пользу new SimpleMongoDbFactory(new MongoClient(), database);.

Итак, мой последний рабочий ответ без предупреждений о том, что это:

@Configuration
public class SpringMongoConfig {

    @Value("${spring.data.mongodb.database}")
    private String database;

    @Autowired
    private MongoDbFactory mongoDbFactory;

    public @Bean MongoDbFactory mongoDBFactory() throws Exception {
        return new SimpleMongoDbFactory(new MongoClient(), database);
    }

    public @Bean MongoTemplate mongoTemplate() throws Exception {

        DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory);

        // Remove _class
        MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, new MongoMappingContext());
        converter.setTypeMapper(new DefaultMongoTypeMapper(null));

        return new MongoTemplate(mongoDBFactory(), converter);

    }

}

Надеюсь, что это поможет людям, которые хотели бы провести чистый класс без предупреждений об испаке.

Это мое решение для линии:

@Bean 
public MongoTemplate mongoTemplateFraud() throws UnknownHostException {

  MongoTemplate mongoTemplate = new MongoTemplate(getMongoClient(), dbName);
  ((MappingMongoConverter)mongoTemplate.getConverter()).setTypeMapper(new DefaultMongoTypeMapper(null));//removes _class
  return mongoTemplate;
}

Я долго боролся с этой проблемой. Я следил за подходом из Mkyong Но когда я представил LocalDate Атрибут (любой класс JSR310 от Java 8) Я получил следующее исключение:

org.springframework.core.convert.ConverterNotFoundException:
No converter found capable of converting from type [java.time.LocalDate] to type [java.util.Date]

Соответствующий преобразователь org.springframework.format.datetime.standard.DateTimeConverters является частью пружины 4.1 и упоминается в Spring Data MongoDB 1.7. Даже если я использовал новые версии, преобразователь не прыгнул.

Решением было использовать существующее MappingMongoConverter и предоставить только новый DefaultMongoTypeMapper (Код из Mkyong находится под комментарием):

@Configuration
@EnableMongoRepositories
class BatchInfrastructureConfig extends AbstractMongoConfiguration
{
    @Override
    protected String getDatabaseName() {
        return "yourdb"
    }

    @Override
    Mongo mongo() throws Exception {
        new Mongo()
    }

    @Bean MongoTemplate mongoTemplate()
    {
        // overwrite type mapper to get rid of the _class column
//      get the converter from the base class instead of creating it
//      def converter = new MappingMongoConverter(mongoDbFactory(), new MongoMappingContext())
        def converter = mappingMongoConverter()
        converter.typeMapper = new DefaultMongoTypeMapper(null)

        // create & return template
        new MongoTemplate(mongoDbFactory(), converter)
    }

Обобщить:

  • продлевать AbstractMongoConfiguration
  • аннотировать с EnableMongoRepositories
  • в mongoTemplate Получить конвертер из базового класса, это гарантирует, что классы конверсии типа зарегистрированы

Вам просто нужно добавить аннотацию @typealias в определение класса по поводу изменения типа Mapper

@Configuration
public class MongoConfig {

    @Value("${spring.data.mongodb.database}")
    private String database;

    @Value("${spring.data.mongodb.host}")
    private String host;

    public @Bean MongoDbFactory mongoDbFactory() throws Exception {
        return new SimpleMongoDbFactory(new MongoClient(host), database);
    }

    public @Bean MongoTemplate mongoTemplate() throws Exception {

        MappingMongoConverter converter = new MappingMongoConverter(new DefaultDbRefResolver(mongoDbFactory()),
                new MongoMappingContext());
        converter.setTypeMapper(new DefaultMongoTypeMapper(null));

        MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory(), converter);

        return mongoTemplate;

    }

}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top