PersistenceConstructor 参数变量名称与实例变量名称不匹配
我正在尝试使用 spring-data-mongodb
版本 1.1.1.RELEASE
持久化以下对象:
I'm trying to persist the following object with spring-data-mongodb
version 1.1.1.RELEASE
:
@Document
public static class TestObject {
private final int m_property;
@PersistenceConstructor
public TestObject(int a_property) {
m_property = a_property;
}
public int property() {
return m_property;
}
}
当我尝试从数据库中读回对象时,我得到了一个 MappingException
(请参阅下面的完整堆栈跟踪)
I get a MappingException
when I try to read the object back from the database (see full stacktrace below)
我的小组使用的命名约定要求参数变量名称以 a_
开头,实例变量名称以 m_
开头.似乎 spring-data-mongodb
假设构造函数参数变量名称必须与对象实例变量名称匹配.
The naming convention my group uses requires argument variable names to be prefaced by a_
and instance variable names to be prefaced by m_
. It seems like spring-data-mongodb
is making the assumption that the constructor argument variable names must match the object instance variable names.
- 为什么
spring-data-mongodb
不使用我在构造函数中定义的实例变量映射的构造函数参数? - 是否有另一种方法来定义此映射,以便
spring-data-mongodb
正确构造我的对象,或者是我唯一的选择来打破命名约定?
- Why doesn't
spring-data-mongodb
use the constructor argument to instance variable mapping that I define within the constructor? - Is there another way to define this mapping such that
spring-data-mongodb
will properly construct my object, or is my only option to break the naming convention?
.
Exception in thread "main" org.springframework.data.mapping.model.MappingException: No property a_property found on entity class com.recorder.TestRecorder$TestObject to bind constructor parameter to!
at org.springframework.data.mapping.model.PersistentEntityParameterValueProvider.getParameterValue(PersistentEntityParameterValueProvider.java:90)
at org.springframework.data.convert.ReflectionEntityInstantiator.createInstance(ReflectionEntityInstantiator.java:70)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:229)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:209)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:173)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:169)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:72)
at org.springframework.data.mongodb.core.MongoTemplate$ReadDbObjectCallback.doWith(MongoTemplate.java:1820)
at org.springframework.data.mongodb.core.MongoTemplate.executeFindMultiInternal(MongoTemplate.java:1542)
at org.springframework.data.mongodb.core.MongoTemplate.findAll(MongoTemplate.java:1064)
at com.recorder.TestRecorder.main(TestRecorder.java:43)
推荐答案
tl;dr
我们需要依赖构造函数参数名称来匹配字段名称来找出要拉入文档的哪个字段.如果要自定义此使用 @Value("#root.field_name")
在构造函数参数上.
We need to rely on constructor argument names to match field names to find out which field of the document to pull in. If you want to customize this use @Value("#root.field_name")
on the constructor argument.
长篇大论
如果您使用带参数的构造函数让 Spring Data 使用此构造函数实例化给定的类,我们必须在调用时将参数传递给构造函数.要找出我们必须提交的文档字段,我们需要检查匹配属性以进行潜在的字段名称自定义.请参阅以下示例:
If you're using a constructor with arguments to let Spring Data instantiate the given class using this constructor we have to hand parameters to the constructor upon invocation. To find out which document field we have to hand in, we need to inspect the matching property for potential field name customization. See the following example:
@Document
class MyEntity {
@Field("foo")
private String myField;
public MyEntity(String myField) {
this.myField = myField;
}
}
在这种情况下,我们需要通过管道将字段 foo
传递到构造函数中,如果我们不能以某种方式获取对属性的引用,就无法找到这一点.如果构造函数参数名称不同,我们应该如何可靠地找出哪个字段值实际上应该用作参数?您在问题中显示的示例可能永远开箱即用,因为您的文档将包含一个 m_property
字段,并且绝对无法找出您真正想要的要注入的,除了添加更显式的配置.
In this case we need to pipe the field foo
into the constructor and there's no way to find out about this if we don't somehow can obtain a reference to the property. If the constructor parameter name was something different, how should we reliably find out which field value should actually be used as argument? The example you've shown in your question can never work out of the box, as your document would contain a m_property
field and there's absolutely no way to find out you actually want that to be injected, except adding more explicit configuration.
要自定义此行为,您可以使用 Spring 的 @Value
注释并将自定义文档字段注入构造函数.文档本身可通过 #root
变量获得.因此,您可以轻松地将我上面的示例更改为:
To customize this behavior you can use Spring's @Value
annotation and inject a custom document field into the constructor. The document itself is available through the #root
variable. So you could easily alter my sample above to:
@Document
class MyEntity {
@Field("foo")
private String myField;
public MyEntity(@Value("#root.foo") String somethingDifferent) {
this.myField = somethingDifferent;
}
}
我强烈建议您将自定义字段名称添加到您的属性中,并且您不想将属性命名约定暴露给数据库.@Value的用法-usage-annotations" rel="noreferrer">参考文档 但我创建了 a票 以改进文档并使其更加明显.
I'd strongly recommend that you add custom field names to your properties as well as you don't want to expose your property naming conventions to the database. The usage pf @Value
is briefly mentioned in the reference docs but I've created a ticket to improve the docs and make this more obvious.
相关文章