我一直在Spring Boot中使用Spring Data MongoDB项目,我看到了我不清楚的行为。我知道id字段将http://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#mapping.conventions.id-field.在Mongo存储库中_id。我的问题是,它似乎也发生在似乎不正确的子实体上。
例如,我有这些类(为了简洁起见,省略了setter和getter):
public class MessageBuild {
@Id
private String id;
private String name;
private TopLevelMessage.MessageType messageType;
private TopLevelMessage message;
}
public interface TopLevelMessage {
public enum MessageType {
MapData
}
}
public class MapData implements TopLevelMessage {
private String layerType;
private Vector<Intersection> intersections;
private Vector<RoadSegment> roadSegments;
}
public class RoadSegment {
private int id;
private String name;
private Double laneWidth;
}
我用它创建了一个对象图我使用适当的MongoRepository类来保存我最终得到了一个这样的示例文档(_class):
{
"_id" : ObjectId("57c0c05568a6c4941830a626"),
"_class" : "com.etranssystems.coreobjects.persistable.MessageBuild",
"name" : "TestMessage",
"messageType" : "MapData",
"message" : {
"layerType" : "IntersectionData",
"roadSegments" : [
{
"_id" : 2001,
"name" : "Road Segment 1",
"laneWidth" : 3.3
}
]
}
}
在这种情况下,一个名为id的字段的子对象将其映射转换为MongoDB存储库中的_id。虽然没有预料到,但这并不是世界末日。现在最大的问题是,这是由REST公开的MVC_id字段不是从查询返回的。我试图在我的RepositoryRestConfigrerAdapter中为这个类设置exopeIdsFor,它公开了顶级文档的id,但没有公开子文档。
所以围绕我的两个问题/问题是:
我认为RoadSegment不包含getId()
是错误的吗?来自Spring的留档:
没有注释但命名为id的属性或字段将映射到_id字段。
我相信Spring Data甚至对嵌套类也这样做,当它找到一个id字段时。您可以添加getId()
,以便将该字段命名为id
或使用@Field
对其进行注释:
public class RoadSegment {
@Field("id")
private int id;
private String name;
private Double laneWidth;
}
在我看来,我同意这种id/_id的自动转换只能在顶层进行。
但是,Spring Data Mongo转换的编码方式,所有java对象都经过完全相同的代码转换为json(顶部和嵌套对象):
public class MappingMongoConverter {
...
protected void writeInternal(Object obj, final DBObject dbo, MongoPersistentEntity<?> entity) {
...
if (!dbo.containsField("_id") && null != idProperty) {
try {
Object id = accessor.getProperty(idProperty);
dbo.put("_id", idMapper.convertId(id));
} catch (ConversionException ignored) {}
}
...
if (!conversions.isSimpleType(propertyObj.getClass())) {
// The following line recursively calls writeInternal with the nested object
writePropertyInternal(propertyObj, dbo, prop);
} else {
writeSimpleInternal(propertyObj, dbo, prop);
}
}
在顶层对象上调用write e内部
,然后为每个子对象递归调用(又名SimpleTypes)。因此,它们都经历了添加_id
的相同逻辑。
也许这就是我们应该如何阅读Spring的留档:
MongoDB要求所有文档都有一个_id字段。如果您不提供,驱动程序将为ObjectId分配一个生成的值。
如果Java类中没有上面指定的字段或属性,则驱动程序将生成一个隐式_id文件,但不会映射到Java类的属性或字段。