Spring 数据 MongoDB @DBRef 为 child class 加载 null

Spring Data MongoDB @DBRef Loads null for child class

我正在尝试将包含 @DBRef 的 object 保存并加载到另一个恰好属于 child class 类型和 Spring 数据 MongoDB 将字段加载为空。

class Person {
    @Id
    private long id;
    @DBRef
    private Food food;
}

class Food {
    @Id
    private long id;
}

class Burger extends Food {}

我正在单独保存 objects:

Burger burger = new Burger();
foodRepository.save(burger);

Person person = new Person();
person.setFood(burger);
personRepository.save(person);

发生的事情是 burger object 保存在 food collection 中,_class 值为 Burger MongoDB 并且 Person 文档中的 $ref 指向 burger 而不是 food.

person collection:

{
    "_id" : NumberLong(1),
    "food" : {
        "$ref" : "burger",
        "$id" : NumberLong(2)
    },
    "_class" : "Person"
}

food collection:

{
    "_id" : NumberLong(2),
    "_class" : "Burger"
}

如果我使用 findAll()findById() 加载 object,则 food 字段为空。但是,如果我将 findByFood() 与汉堡 object 一起使用,则会返回人 object。我在这里没有正确理解什么?

personRepository.findById(1L).getFood(); // null
personRepository.findByFood(burger);     // Person object

Christoph Strobl 在 Spring Data MongoDB JIRA board 中回答了这个问题。将他的答案粘贴在下面以防万一有人找到这个。我个人选择了选项 1 来解决我的问题。


通过 Repository 保存不同类型的食物使用 Repository 接口类型参数来确定实际的 MongoDB 集合。 在这种情况下,Food 的所有子类型将最终出现在食物集合中,除非它们通过 @Document 注释的集合属性明确重定向。

另一方面,Person 存储库不知道 Food Repository 和到 food 集合的集合路由。因此映射在 Person#food 中看到 Burger 实体并创建对汉堡集合的引用,然后无法解析,导致您看到的空值。

{
    "_id" : 1,
    "food" : {
        "$ref" : "burger",
        "$id" : 1
    },
    "_class" : "Person"
}

您可以尝试以下方法之一:

  1. 使用@Document注解并显式命名集合来存储Food及其子类型,以便映射层可以正确设置$ref。
@Document("food")
class Food {
    @Id private long id;
}
  1. 使用 MongoOperations#save 保存食物。这样每个子类都会在自己的集合中结束,这样就可以解析 "$ref" : "burger"。