3

我一直在 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 字段的配置是否不应该适用于文档中的子对象?
4

1 回答 1

2

我认为 RoadSegment 不包含 a 是错误的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);
        }
}

writeInternal在顶层对象上调用,然后为每个子对象(又名 SimpleTypes)递归调用。所以他们都经历了相同的添加逻辑_id

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

  • Mongo 对Mongo Documents的限制:

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

  • Spring Data 对java 类的限制:

如果Java 类中不存在上面指定的字段或属性, 则驱动程序将生成一个隐式 _id 文件,但不会映射到Java 类的属性或字段。

于 2016-08-29T22:39:05.323 回答