5

我試圖用1.1.1.RELEASEspring-data-mongodb版本堅持以下對象:PersistenceConstructor參數變量名稱不匹配的實例變量名

@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

這真是糟糕的命名約定,沒有任何意義。 –

回答

16

TL;博士

我們需要依靠構造函數的參數名稱相匹配字段名找出拉文檔的哪些領域。如果你想定製的構造函數的參數此使用@Value("#root.field_name")

說來話長

如果您使用帶有參數的構造函數來讓Spring數據使用此構造,我們不得不手工參數來調用時的構造實例給定的類。爲了找出我們必須交付的文檔字段,我們需要檢查匹配屬性以獲取潛在的字段名稱定製。請看下面的例子:

@Document 
class MyEntity { 

    @Field("foo") 
    private String myField; 

    public MyEntity(String myField) { 
    this.myField = myField; 
    } 
} 

在這種情況下,我們需要管領域foo到構造,有沒有辦法找出這個如果不以某種方式可以獲得對屬性的引用。如果構造函數的參數名稱不同,我們應該如何可靠地找出哪個字段值應該被實際用作參數?您在問題中顯示的示例從不開箱即用,因爲您的文檔將包含m_property字段,除了添加更多顯式配置外,絕對沒有辦法找到實際上希望注入的內容。

要自定義此行爲,您可以使用Spring的註釋並在構造函數中注入自定義文檔字段。該文件本身可通過#root變量獲得。所以,你可以很容易地改變我的樣品上面:

@Document 
class MyEntity { 

    @Field("foo") 
    private String myField; 

    public MyEntity(@Value("#root.foo") String somethingDifferent) { 
    this.myField = somethingDifferent; 
    } 
} 

我強烈建議您添加自定義字段名稱到您的性質以及你不想暴露你的財產命名約定到數據庫。在reference docs中簡要提及了使用pf @Value,但我創建了a ticket以改進文檔並使其更加明顯。

+0

對你的一個後續問題 - 如果我按你的建議做,它似乎適用於只包含基元的對象,但每當我嘗試使用包含其他對象的對象時,我都會遇到異常。你知道這裏發生了什麼嗎?我在[問題13854753](http://stackoverflow.com/questions/13854753)中列出了詳細信息。 –

+0

僅供參考 - 我創建了[DATAMONGO-592](https://jira.springsource.org/browse/DATAMONGO -592)來跟蹤不能使用包含其他對象的對象的問題。謝謝你的幫助!! –

+0

哦,我喜歡stackoverflow和那些誰貢獻!我可能花了幾天的時間試圖弄清楚什麼是錯誤的,你只是一直救了我,並且感到沮喪。謝謝! – TheZuck

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> 

看到this reference

旁註:這是一個變通,我不認爲命名約定意味着如此緊張以至於你需要解決問題。也許是時候讓你的團隊「重新思考」那些命名約定(在這種情況下,爲了生產效率)。