2015-06-22 45 views
4

我有一個Spring庫如下:如何使用構造函數映射與Spring JPA存儲庫

import org.springframework.data.repository.Repository; 
import org.springframework.stereotype.Component; 

import com.test.domain.My; 

@Component 
public interface MyRepository extends Repository<My, String> { 

    My findOne(String code); 

    My findByName(String name); 

} 

實體類是:

import javax.persistence.ColumnResult; 
import javax.persistence.ConstructorResult; 
import javax.persistence.Entity; 
import javax.persistence.Id; 
import javax.persistence.SqlResultSetMapping; 
import javax.persistence.Table; 

import com.fasterxml.jackson.annotation.JsonCreator; 
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 
import com.fasterxml.jackson.annotation.JsonProperty; 

@JsonIgnoreProperties(ignoreUnknown=true) 
@Entity 
@Table(name="vMy", schema="test") 
@SqlResultSetMapping(
    name="something", 
    classes = { 
     @ConstructorResult(targetClass = My.class, 
      columns={ 
       @ColumnResult(name = "myCode", type = String.class), 
       @ColumnResult(name = "myShortName", type = String.class) 
      } 
     ) 
    } 
) 
public class My { 

    @Id 
    @Column(name = "myCode") 
    private final String code; 

    @Column(name = "myShortName") 
    private final String name; 

    public My(String code, String name) { 
     this.code = code; 
     this.name = name; 
    } 

    @JsonCreator() 
    public My(@JsonProperty("My_c") String code) { 
     this.code = code; 
     this.name = null; 
    } 

    public String getCode() { 
     return code; 
    } 

    public String getName() { 
     return name; 
    } 

    @Override 
    public String toString() { 
     return "{code: " + code + ", name: " + name + "}"; 
    }  
} 

當findOne或findByName被調用時,下面的錯誤是給定:

org.hibernate.InstantiationException: No default constructor for entity 

我如何使用Spring JPA存儲庫,而不是默認的構造函數?我想保留實例字段,代碼和名稱,最終。

+1

您的實體沒有**任何**構造函數,除非'public Portfolio'應該是構造函數。爲什麼你需要你的實體的領域是'最終'?我從未在任何實體中看到過。 – DuncanKinnear

+0

是的,公衆組合應該是構造者。我將它改爲公開我的。我希望實體的字段是最終的,這樣一旦實體被創建,它的狀態就不能被改變(即不可變)。 – James

+0

我認爲你可能混合了實體和DTO(數據傳輸對象)的角色。雖然EJB3允許實體與數據庫層分離,這是對EJB2的重大改進,但DTO的角色在EJB3中仍然是有效的。您的最終字段更多地位於DTO而不是實體。如果您將這些實體字段最終確定,您將如何修改這些實體。雖然現在可能不是一個需求,但誰知道你的應用程序在將來需要做什麼。我不會對我的實體及其領域施加如此大的限制。 – DuncanKinnear

回答

2

我會創建一個名爲MyDto的獨立類,它具有JSON內容,但不包含實體註釋。使它成爲最終的領域。

然後你的資料庫的方法將是這樣的:

@Query("SELECT new MyDto(m.code, m.name) FROM My m WHERE m.code = :code") 
public MyDto findByCode(@Param("code") String code); 

這樣,你只使用我的實體類給你映射到數據庫列,沒有創造的My一個實例。


編輯:另一種方法(as detailed here)是使用實體類本身作爲DTO。

所以,你的查詢方法看起來是這樣的:

@Query("SELECT new My(m.code, m.name) FROM My m WHERE m.code = :code") 
public My findByCode(@Param("code") String code); 

這有沒有創建一個單獨的DTO類的優勢。

+1

我不確定我是否遵守。你是否想讓存儲庫方法(findByCode)返回一個MyDto實例?如果是這樣,我看起來怎麼樣? – James

+0

是的,該方法將返回一個DTO而不是一個實體。 「我的」課程可以完全按照您現在的方式進行。它並不重要,因爲它僅用於定義ORM(對象關係映射)。你永遠不會實例化一個'My'的實例。 – DuncanKinnear

+1

JPA 2.1規範聲明「實體類必須具有無參數構造函數」&「實體類沒有方法或持久化實例變量可能是最終的。」我注意到一些暗示不變性,通過提供一個受保護的無參數構造函數和沒有setter(例如[Spring Data example](https://github.com/spring-projects/spring-data-book/blob/1db59b77bea7139ee54a0bdb62c38e9cfc82c432/jpa /src/main/java/com/oreilly/springdata/jpa/core/Address.java)。然而,你的答案實際上允許在沒有無參數構造函數和所有最終字段的情況下定義實體。(+1)。 – James

相關問題