Spring Data Mongodb - 处理包含不同类型的集合的存储库

7

我有一个Mongo集合,可能包含三种实体类型,我将其映射到Java类型:

  • 节点
  • LeafType1
  • LeafType2

该集合用于使用父条目中的子节点的dbRef存储树状结构。

在Spring参考文档中,我没有找到关于这个主题的任何信息,所以我在这里问:是否有一种方法可以使用Repository机制处理可能包含不同类型对象的集合?

声明几个不同类型的存储库在一个集合中似乎不是很好的想法,因为我总是在处理查询对象不是预期类型的情况,并且创建一个抽象类的存储库,所有可能的类型都继承该类似乎行不通。

为了说明我的意思:

/**
 * This seems not safe
 */
public interface NodeRepository extends MongoRepository<Node, String> { }
public interface LeafType1Repository extends MongoRepository<LeafType1, String> { }
public interface LeafType2Repository extends MongoRepository<LeafType2, String> { }

/**
 * This doesn't work at all
 */
public interface MyCollectionRepository extends MongoRepository<AbstractMyCollectionNode, String> { }
2个回答

7
如果Node\LeafType1\LeafType2是AbstractMyCollectionNode的子类,那么事情就简单了。只需像写作一样声明仓库即可:
public interface MyCollectionRepository extends MongoRepository<AbstractMyCollectionNode, String> { }

我们在一个项目中实现了这个功能,效果很好。Spring Data会在MongoDB集合中的文档中添加一个名为“_class”的属性,以便确定应该实例化哪个类。
存储在一个集合中的文档可能具有某些相似性,也许可以为它们提取一个通用类。
以下是我们其中一个项目中复制的一些代码:
实体:
public abstract class Document {
    private String id;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
    ....

public class WebClipDocument extends Document {
    private String digest;
    ...

代码仓库:

public interface DocumentDao extends MongoRepository<Document, String>{
...

而且,如果你的mongodb集合中的文档没有"_class"属性。你可以使用转换器

在存储和查询对象时,拥有一个MongoConverter实例来处理所有Java类型到DBObject的映射是很方便的。然而,有时您可能希望`MongoConverter`完成大部分工作,但允许您选择性地处理特定类型的转换或优化性能。


我尝试过了,但是不起作用。例如,如果我按ID进行提取,就会出现一个错误,指出无法直接实例化抽象对象。看起来你建议的仓库配置不知道要使用哪个类来映射返回的值。如果这对你有用,请详细说明你的配置,谢谢。 - Alex
@SimY4,我已经更新了答案。我认为关键点可能是“_class”属性。 - Leon
我在阅读了Spring Data的参考文献并找到了“转换器”之后,又更新了答案。 - Leon
那么类型检查呢?你的存储库将返回类型为“Document”的对象。你是否总是执行返回类型的检查以确定是否获得所需的条目? - Alex
是的,我们会检查并将文档对象强制转换为实际类型。 - Leon
1
但是您不会失去WebClipDocument的字段。 - Sercan Ozdemir

4

Spring Data使用Repository-Declarations作为入口点来查找实体类(它不直接扫描包中的实体)。

所以,您只需要为子类声明一个“未使用”的Repository-Interface,就像您在原始帖子中提出的“不安全”一样:

public interface NodeRepository extends MongoRepository<Node, String> { 
  // all of your repo methods go here
  Node findById(String id);
  Node findFirst100ByNodeType(String nodeType);
  ... etc.
}
public interface LeafType1Repository extends MongoRepository<LeafType1, String> {
  // leave empty
}
public interface LeafType2Repository extends MongoRepository<LeafType2, String> { 
  // leave empty
}

你不必使用额外的LeafTypeX存储库,可以使用NodeRepository来存储和查找LeafType1LeafType2类型的对象。但是需要声明另外两个存储库,以便在初始扫描时将LeafType1LeafType2作为实体找到。
PS:这一切都假设你的LeafType1LeafType2类上有@Document(collection= "nodes")注释。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接