使用Spring 5.0.6和Spring-Data-Mongo 2.0.7,在将实体转换为错误的类时,我遇到了一个问题。请参阅以下简化方案:
实体设置:
public class PersistableObject {
@Id @Field("_id") private String id;
}
@Document(collection = "myapp_user")
public class User extends PersistableObject {...}
public class RealUser extends User {...}
public class VirtualUser extends User {...}
因此,有一个共同的MongoDB 集合存储两种类型的User
,由自动添加的 _class 属性区分。
此外,还有一个注册了MongoTemplate的Repository。
@Autowired
private org.springframework.data.mongodb.core.MongoTemplate template;
到目前为止一切都很好。现在,如果我想获取包含RealUser
的所有文档,我可以将其称为
template.findAll(RealUser.class)
我希望模板找到所有将 _class 设置为com.myapp.domain.RealUser
的鉴别器属性的文档。
但这并不像预期的那样奏效。我甚至将所有VirtualUser
放入RealUser
类型的对象中,其中缺少所有特定于VirtualUser的属性,并且所有特定于RealUser的属性都设置为null
。
此外,当我去保存一个User
,它实际上是MongoDB中的VirtualUser
,但已被挤入RealUser
类时,Spring将更改_class
} -property为错误的类型,神奇地将VirtualUser
转换为RealUser
。
所以这里的两个方法都会加载整个集合并将所有对象压缩到指定的类中,即使它是错误的:
template.findAll(VirtualUser.class)
template.findAll(RealUser.class)
这种行为可能是不可取的,或者如果是这样,那么它极具误导性和危害性。您可以使用此功能轻松切碎整个数据。
任何人都可以对此有所了解吗?
答案 0 :(得分:1)
我在Spring的Jira创建了一个ticket。在下面找到Olivers评论:
该方法实际上按预期工作,但我同意我们需要 改进JavaDoc。该方法基本上指定为“加载 给定类型的文档被配置为持久化并映射所有文档 它们(因此名称)到给定类型“。给它的类型不是 同时用作类型映射标准。每一个限制 您想要申请退回的文件需要应用 通过一个Query实例,它暴露了一个... .restrict(...)方法 只允许选择带有类型信息的文档。
findAll以其工作方式工作的原因通常是 说 - 即没有继承方案 - 我们需要 能够阅读所有文件,即使他们没有任何类型 信息。假设一个集合包含代表人的文档 尚未使用Spring Data编写的。如果一个 findAll(Person.class)应用类型限制,调用将返回 即使有文件存在也没有文件。不幸的是我们 不知道要查询的集合是否携带类型 信息。事实上,有些文件可能带有类型信息, 有些人可能没有。合理控制这个的唯一方法就是让 用户决定,她可以通过调用Query.restrict(...)来实现。 前者仅选择具有类型信息的文档,后者。
正如我所说,我完全看到JavaDoc可能会误导这里。 我要用这张票来改进。很想听听 Query.restict(...)的使用允许你实现你想要的。