我正在尝试使用spring-data-mongodb
版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
(参见下面的完整堆栈跟踪)
我的小组使用的命名约定要求参数变量名称以a_
开头,实例变量名称以m_
开头。似乎spring-data-mongodb
假设构造函数参数变量名必须与对象实例变量名匹配。
spring-data-mongodb
不将构造函数参数用于我在构造函数中定义的实例变量映射? spring-data-mongodb
能够正确构建我的对象,或者是我打破命名约定的唯一选择?
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)
答案 0 :(得分:17)
<强> TL;博士强>
我们需要依赖构造函数参数名来匹配字段名,以找出要引入的文档的哪个字段。如果要自定义它,请在构造函数参数上使用@Value("#root.field_name")
。
长篇故事
如果你使用带参数的构造函数让Spring Data使用这个构造函数实例化给定的类,我们必须在调用时将参数传递给构造函数。要找出我们必须提交的文档字段,我们需要检查匹配属性以进行潜在的字段名称自定义。请参阅以下示例:
@Document
class MyEntity {
@Field("foo")
private String myField;
public MyEntity(String myField) {
this.myField = myField;
}
}
在这种情况下,我们需要将字段foo
传递给构造函数,如果我们不能以某种方式获取对该属性的引用,则无法找到它。如果构造函数参数名称不同,我们应该如何可靠地找出实际上应该将哪个字段值用作参数?您在问题中显示的示例永远不会开箱即用,因为您的文档将包含m_property
字段,并且绝对没有办法找出您实际上希望它是注入,除了添加更明确的配置。
要自定义此行为,您可以使用Spring的@Value
注释并将自定义文档字段注入构造函数。文档本身可通过#root
变量获得。因此,您可以轻松地将上面的示例更改为:
@Document
class MyEntity {
@Field("foo")
private String myField;
public MyEntity(@Value("#root.foo") String somethingDifferent) {
this.myField = somethingDifferent;
}
}
我强烈建议您在属性中添加自定义字段名称,并且不希望将属性命名约定公开给数据库。 reference docs中简要提及了@Value
的使用情况,但我创建了a ticket以改进文档并使其更加明显。
答案 1 :(得分:0)
您可以使用一些自定义转换器(并删除@PersistenceConstructor
):
// DB => Java
package com.recorder.converters;
public class TestObjectReadConverter implements Converter<DBObject, TestObject>
{
public TestObject convert(final DBObject source) {
return new TestObject((Integer) source.get("m_property"));
}
}
// JAVA => DB
package com.recorder.converters;
public class TestObjectWriteConverter implements Converter<TestObject, DBObject>
{
public DBObject convert(final TestObject source) {
return new BasicDBObjectBuilder("m_property", source.property()).get();
}
}
不要忘记声明那些(xml配置):
<mongo:mapping-converter base-package="com.recorder">
<mongo:custom-converters>
<mongo:converter>
<bean class="com.recorder.converters.TestObjectReadConverter" />
</mongo:converter>
<mongo:converter>
<bean class="com.recorder.converters.TestObjectWriteConverter"/>
</mongo:converter>
</mongo:custom-converters>
</mongo:mapping-converter>
旁注:这是一个解决方法,我不认为命名约定太紧,你需要解决。或许现在是时候让你的小组“重新思考”那些命名惯例(为了生产效率)。