Spring数据Mongo - 如何映射继承的POJO实体?
Spring Data Mongo - How to map inherited POJO entities?
我是 Spring 的新手,但我想尝试一下这个项目。
我有一个 MongoDB 数据库,其中填充了相当复杂的文档。我想使用 Spring 数据 Mongo 来查询(没有其他 CRUD 操作)数据库。
我已经使用 POJO 描述了我的文档实体,但其中一些是抽象的(参见 GeometryGeoJSON
用于接受所有类型的 GeoJson 几何,或 Contact
可以是 Person
或 Organisation
。下面提供 GitHub 存储库的 link。
对该实体定义进行测试,抛出 java.lang.InstantiationError
是公平的,因为在那些抽象 类.
中没有定义构造函数
这里是GitHub repository,以备不时之需。
我对这一切感到有点迷茫,但我会更仔细地查看文档。
你会如何面对这个问题?
我会回答我自己的问题。如评论中所述,解决方案是使用 Converter
.
这是我打算用我的 class 模型实现的示例:
A Contact
可以是 Person
或 Organisation
。
如果您正在使用 spring-data-mongodb MongoRepository to write data in your database according to your entity model, a _class
field will be added to document roots and to complex property types (see this section)。此字段存储 Java class 的完全限定名称,它允许在从 MongoDb 文档映射到 Spring 数据模型时消除歧义。
如果您的应用程序只是从数据库中读取文档(没有 _class
字段),您需要告诉 Spring 数据在映射 Contact
时要实例化哪个 class . Spring-data 允许您使用 Converter
自定义默认类型映射行为。使用显式 Converter
override default mapping for the class。您需要明确映射整个 class。这是我的 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);
}
}
希望对您有所帮助。
我是 Spring 的新手,但我想尝试一下这个项目。 我有一个 MongoDB 数据库,其中填充了相当复杂的文档。我想使用 Spring 数据 Mongo 来查询(没有其他 CRUD 操作)数据库。
我已经使用 POJO 描述了我的文档实体,但其中一些是抽象的(参见 GeometryGeoJSON
用于接受所有类型的 GeoJson 几何,或 Contact
可以是 Person
或 Organisation
。下面提供 GitHub 存储库的 link。
对该实体定义进行测试,抛出 java.lang.InstantiationError
是公平的,因为在那些抽象 类.
这里是GitHub repository,以备不时之需。
我对这一切感到有点迷茫,但我会更仔细地查看文档。
你会如何面对这个问题?
我会回答我自己的问题。如评论中所述,解决方案是使用 Converter
.
这是我打算用我的 class 模型实现的示例:
A Contact
可以是 Person
或 Organisation
。
如果您正在使用 spring-data-mongodb MongoRepository to write data in your database according to your entity model, a _class
field will be added to document roots and to complex property types (see this section)。此字段存储 Java class 的完全限定名称,它允许在从 MongoDb 文档映射到 Spring 数据模型时消除歧义。
如果您的应用程序只是从数据库中读取文档(没有 _class
字段),您需要告诉 Spring 数据在映射 Contact
时要实例化哪个 class . Spring-data 允许您使用 Converter
自定义默认类型映射行为。使用显式 Converter
override default mapping for the class。您需要明确映射整个 class。这是我的 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);
}
}
希望对您有所帮助。