我遇到了一个问题,试图将继承与MongoDB视图和@CompoundIndex
结合使用。说我有一个集合items
和该集合的视图称为itemsView
。我在我的模型中代表这些实体,如下所示:
@Document(collection = "items")
@CompoundIndex(name = "view_active_available" def = "{active: 1, quantity: 1}")
public class Item {
// Adding index on collection that view definition will leverage
}
然后,对于视图,我想扩展Item
类,以便在从视图中读取时可以利用其成员,getter / setter等,如下所示:
@Document(collection = "itemsView")
public class ItemAvailable extends Item {
// Now I can read from the view but treat them as `Item` instances
}
知道在视图上创建索引是不可能的,我检查了Spring Data MongoDB源代码以获取@CompoundIndex
注释,并发现:
/**
* Mark a class to use compound indexes.
* ...
*/
@Target({ ElementType.TYPE })
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface CompoundIndex {
...
}
完美,@CompoundIndex
不是@Inherited
所以这应该工作正常,我想。所以我构建并启动了我的应用程序,遗憾地遇到了这个问题:
org.springframework.beans.factory.BeanCreationException:创建名为'itemsView'的bean时出错:init方法的调用失败;嵌套异常是org.springframework.data.mongodb.UncategorizedMongoDbException:命令失败,错误166:'无法在视图上创建索引'
所以,Spring毕竟试图在视图上创建索引。
我正在努力实现的目标似乎是在处理视图(以及它们的实体,它们毕竟只是一个“普通的”非视图实体)时必然是一个常见的设计挑战。
为什么非继承的@CompoundIndex
注释应用于子类?
更新:经过大量调试后,我相信这可能是Spring Data MongoDB中的一个错误。 MongoPersistentEntintyIndexResolver
有一个potentiallyCreateCompoundIndexDefinitions
方法,明确检查所讨论的类(实体)上是否存在@CompoundIndexes
和@CompoundIndex
。它是通过调用Spring Data的BasicPersistentEntity.findAnnotation
方法实现的。该方法遍历继承链,查找指定的注释,如果找到它,则返回它,无论它在类层次结构中的位置如何。在potentiallyCreateCompoundIndexDefinitions
(或其他任何地方)没有检查是否在超类上找到了注释,如果是,那么是否存在@Inherited
注释。
Spring Framework在查找注释时使用自己的逻辑,默认情况下会检查已实现的接口和超类类型。 @Inherited
没有任何改变。
无论如何,正如我记得当我遇到类似的问题时,没有办法避免继承复合索引。
Spring Data MongoDB的MongoPersistentEntityIndexResolver调用内部私有方法potentiallyCreateCompoundIndexDefinitions
,传递它正在检查的BasicPersistentEntity。该方法反过来调用实体的findAnnotation方法,最终推迟到AnnotatedElementUtils.findMergedAnnotation。
从该课程的文档:
支持@Inherited
获取语义后的方法将遵循Java的@Inherited注释的约定,除了本地声明的注释(包括自定义组合注释)将优先于继承注释。相反,查找语义之后的方法将完全忽略@Inherited的存在,因为查找搜索算法手动遍历类型和方法层次结构,从而隐式支持注释继承而不需要@Inherited。
因此,根据此文档,我遇到的行为是正确的。但是我相信这是Spring Data MongoDB的一个错误 - 要正确地尊重@Inherited
,它需要调用get
注释方法之一而不是find
方法,以防止继承非@Inherited
注释。