40

デフォルトのMappingMongoConverterは、データベース内の各オブジェクトにカスタム タイプ キー (「_class」) を追加します。したがって、Person を作成すると、次のようになります。

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

そしてそれをdbに保存します:

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

mongo の結果のオブジェクトは次のようになります。

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

質問:

  1. Person クラスを別の名前空間に移動すると、どのような影響がありますか?

  2. 「_class」キーでオブジェクトを汚染しないことは可能ですか? Person クラス専用の独自のコンバーターを作成せずに?

4

12 に答える 12

32

これがストーリーです。実際にどのクラスをインスタンス化するかの何らかのヒントとして、デフォルトでタイプを追加します。いずれにせよ、ドキュメントを経由して読み取るために型をパイプする必要があるため、MongoTemplate2 つの可能なオプションがあります。

  1. 実際に格納されている型を割り当てることができる型を渡します。その場合、格納された型を考慮し、それをオブジェクトの作成に使用します。ここでの古典的な例は、ポリモーフィック クエリの実行です。抽象クラスContactPerson. Contactその後、 s を照会できます。基本的に、インスタンス化する型を決定する必要があります。
  2. 一方、完全に異なる型を渡した場合、実際にドキュメントに格納されている型ではなく、指定された型にマーシャリングするだけです。これで、タイプを移動するとどうなるかという質問がカバーされます。

タイプ情報を実際のタイプに変換するための、ある種のプラグ可能なタイプ マッピング戦略をカバーするこのチケットを見ることに興味があるかもしれません。これは、長い修飾クラス名を数文字のハッシュに短縮したい場合があるため、単にスペースを節約する目的で役立ちます。また、別のデータストア クライアントによって生成された完全に任意の型キーを見つけて、それらを Java 型にバインドする、より複雑な移行シナリオも可能になります。

于 2011-07-25T19:08:39.263 に答える
17

ここに私の注釈がありますが、うまくいきます。

@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;

    }

}
于 2012-09-12T13:54:53.993 に答える
5
<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>
于 2013-06-15T06:07:09.847 に答える
3

これは私の1行の解決策です:

@Bean 
public MongoTemplate mongoTemplateFraud() throws UnknownHostException {

  MongoTemplate mongoTemplate = new MongoTemplate(getMongoClient(), dbName);
  ((MappingMongoConverter)mongoTemplate.getConverter()).setTypeMapper(new DefaultMongoTypeMapper(null));//removes _class
  return mongoTemplate;
}
于 2016-07-15T08:09:24.210 に答える
2

私はこの問題に長い間苦労しました。mkyongのアプローチに従いましたが、属性 (Java 8 の JSR310 クラス) を導入するLocalDateと、次の例外が発生しました。

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は Spring 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
  • 基本クラスからのmongoTemplateget コンバーターでは、これにより、型変換クラスが確実に登録されます。
于 2016-03-04T15:41:59.440 に答える
0

上記の解決策を試しましたが、監査と組み合わせて機能しないものもあり、正しく設定されていないようですMongoCustomConversions

私のために働く解決策は次のとおりです

@Configuration
public class MongoConfig {

    @Bean
    public MappingMongoConverter mappingMongoConverterWithCustomTypeMapper(
            MongoDatabaseFactory factory,
            MongoMappingContext context,
            MongoCustomConversions conversions) {
        DbRefResolver dbRefResolver = new DefaultDbRefResolver(factory);
        MappingMongoConverter mappingConverter = new MappingMongoConverter(dbRefResolver, context);
        mappingConverter.setCustomConversions(conversions);

        /**
         * replicate the way that Spring
         * instantiates a {@link DefaultMongoTypeMapper}
         * in {@link MappingMongoConverter#MappingMongoConverter(DbRefResolver, MappingContext)}
         */
        CustomMongoTypeMapper customTypeMapper = new CustomMongoTypeMapper(
                context,
                mappingConverter::getWriteTarget);
        mappingConverter.setTypeMapper(customTypeMapper);
        return mappingConverter;
    }
}

public class CustomMongoTypeMapper extends DefaultMongoTypeMapper {

    public CustomMongoTypeMapper(
            MappingContext<? extends PersistentEntity<?, ?>, ?> mappingContext,
            UnaryOperator<Class<?>> writeTarget) {
        super(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY, mappingContext, writeTarget);
    } 

    @Override
    public TypeInformation<?> readType(Bson source) {

    /**
     * do your conversion here, and eventually return
     */
    return super.readType(source);
    }
}

別の方法として、 を使用しBeanPostProcessorて の作成を検出し、mappingMongoConverterそこにコンバーターを追加することもできます。

何かのようなもの

public class MappingMongoConverterHook implements BeanPostProcessor {
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if ("mappingMongoConverter" == beanName) {
            ((MappingMongoConverter) bean).setTypeMapper(new CustomMongoTypeMapper());
        }
        return bean;
    }
}
于 2021-05-06T21:35:00.920 に答える