Spring Data Mongo-如何映射继承的POJO实体?

时间:2018-11-07 16:57:13

标签: java spring mongodb spring-data spring-data-mongodb

我对Spring还是很陌生,但是我想尝试一下这个项目。 我有一个非常复杂的文档填充的MongoDB数据库。我想使用Spring数据Mongo查询(没有其他CRUD操作)数据库。

我已经使用POJO描述了我的文档实体,但是其中一些是抽象的(请参阅GeometryGeoJSON用于接受所有类型的GeoJson几何图形,或者可以是Contact的{​​{1}}或Person。下面提供了指向GitHub存储库的链接。

使用该实体定义进行测试后,会抛出Organisation,这很公平,因为在这些抽象类中未定义任何Contructor。

这里是GitHub repository,以备不时之需。

我对这一切感到有点迷茫,但我会更仔细地阅读文档。

您将如何面对这个问题?

1 个答案:

答案 0 :(得分:0)

我会回答我自己的问题。如评论中所述,解决方案是使用Converter

这是我打算通过班级模型实现的示例:

enter image description here

Contact可以是PersonOrganisation

如果您正在使用spring-data-mongodb MongoRepository根据您的实体模型在数据库中写入数据,则会将_class字段添加到文档根目录和复杂的属性类型({{ 3}})。该字段存储Java类的完全限定名称,在从MongoDb文档映射到Spring数据模型时,它可以消除歧义。

如果您的应用只是从数据库中读取文档(没有_class字段),则需要告诉Spring数据在映射Contact时要实例化哪个类。 Spring-data允许您使用Converter自定义默认类型映射行为。使用显式Converter see this section。您需要显式映射整个类。这是我的 ContactReadConverter 的示例:

@ReadingConverter
public class ContactReadConverter implements Converter<Document, Contact> {

    @Override
    public Contact convert(Document source) {
        if (source.get("firstName") == null) {
            Organisation organisation = new Organisation();
            I18n name = new I18n();
            name.setEn(source.get("name", Document.class).get("en", String.class));
            name.setFr(source.get("name", Document.class).get("fr", String.class));
            organisation.setName(name);
            organisation.setAcronym(source.get("acronym", String.class));
            organisation.setRole(source.get("role", String.class));
            return organisation;
        }
        Person person = new Person();
        person.setFirstName(source.get("firstName", String.class));
        person.setLastName(source.get("lastName", String.class));
        person.setRole(source.get("role", String.class));
        person.setEmail(source.get("email", String.class));
        person.setOrcId(source.get("orcId", String.class));
        if (source.get("organisation") != null) {
            Document sourceOrg = source.get("organisation", Document.class);
            Organisation organisation = new Organisation();
            organisation.setAcronym(sourceOrg.get("acronym", String.class));
            organisation.setRole(sourceOrg.get("role", String.class));
            if (sourceOrg.get("name") != null) {
                I18n name = new I18n();
                name.setFr(sourceOrg.get("name", Document.class).get("fr", String.class));
                name.setEn(sourceOrg.get("name", Document.class).get("en", String.class));
                organisation.setName(name);
            }
            person.setOrganisation(organisation);
        }
        return person;
    }
}

然后,需要注册新定义的转换器:

@Configuration
public class DataportalApplicationConfig extends AbstractMongoConfiguration {
    @Value("${spring.data.mongodb.uri}")
    private String uri;
    @Value("${spring.data.mongodb.database}")
    private String database;
    @Override
    public MongoClient mongoClient() {
        return new MongoClient(new MongoClientURI(uri));
    }
    @Override
    protected String getDatabaseName() {
        return database;
    }    
    @Bean
    @Override
    public MongoCustomConversions customConversions() {
        List<Converter<?, ?>> converterList = new ArrayList<>();
        converterList.add(new ContactReadConverter());
        return new MongoCustomConversions(converterList);
    }
}

希望有帮助。