在Spring Data Mongo中为子对象

时间:2016-08-29 21:52:26

标签: spring-boot spring-mongodb

我一直在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字段不会从查询中返回。我试图在我的RepositoryRestConfigurerAdapter中为这个类设置exposeIdsFor,它公开了顶级文档的id,但不公开子级文档的id。

围绕我遇到的两个问题:

  • 为什么子对象字段映射到_id?我的理解是,这应该只发生在顶层,因为下面的东西本身并不是真正的文档。
  • 如果映射字段名称,那么公开id字段的配置是否不适用于文档中的子对象?

1 个答案:

答案 0 :(得分:0)

我认为RoadSegment不包含getId()我错了吗?来自Spring's documentation

  

将映射没有注释但名为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对象都通过 exact 相同的代码转换为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);
        }
}
在顶级对象上调用

writeInternal,然后为每个子对象(也称为SimpleTypes)递归调用。所以他们都遵循添加_id的相同逻辑。

也许这就是我们应该如何阅读Spring的文档:

  • Mongo对 Mongo文档
  • 的限制
  

MongoDB要求所有文档都有一个_id字段。如果你   不提供一个驱动程序将分配一个生成的ObjectId   值。

  • Spring Data对 java类的限制:
  

如果 Java类中没有上面指定的字段或属性   然后驱动程序将生成隐式_id文件,但不会   映射到 Java类的属性或字段。