2017-06-22 76 views
0

我想堅持到DB 2實體:映射Java泛型字符串值

  • 屬性

    @Entity 
    public class Attribute<T> { 
    
    @Id @GeneratedValue(strategy = AUTO) 
    Long id; 
    
    @ManyToOne @JoinColumn(name = "item_id") 
    Item item; 
    
    String name; 
    
    T value; 
    
    boolean isTemplate; 
    // skip setter and getter 
    } 
    
  • 項目

    public class Item { 
    
    @Id 
    @GeneratedValue(strategy = AUTO) 
    Long id; 
    
    @OneToMany(cascade = ALL) 
    @JoinColumn(name= "item_id") 
    List<Attribute> attributes; 
    
    private boolean isTemplate; 
        // skip setter and getter 
    } 
    
    in short Item 1-->* Attribute 
    
  • 錯誤消息,我得到的,因爲Hibernate不能映射T值;

    所致:org.springframework.beans.BeanInstantiationException:無法實例[org.hibernate.SessionFactory實例]:出廠方法 '的sessionFactory' 拋出異常;嵌套的異常是org.hibernate.AnnotationException:屬性domain.item.Attribute.value具有未綁定的類型和沒有明確的目標實體。解決這個一般使用問題,或者設定一個明確的目標屬性(如@OneToMany(目標=),或使用一個明確的@Type

  • 我只需要這個簡單的表

    • 項目
      | ID: INT | isTemplate:布爾|
    • 屬性
      | ID:INT |名稱:字符串|類型:字符串(例如:字符串,整數 - >基於價值型)|值:字符串| fk_item_id |

在此先感謝您提供任何幫助或建議以解決此問題。

回答

2

由於java類型擦除Type Erasure,您不能堅持通用T.類型T只在源中存在,在運行時它的類型爲Object。休眠doent的知道如何存儲/呈現數據庫中的對象它可能是任何類型 - 實體,集合,嵌入對象,一些簡單的對象 - 字符串,整數.....

也在關係數據庫中,你不能堅持java沒有適當類型的對象(可以嘗試序列化對象,並將其保存爲BLOB和Java方面去序列化:) :))

一般:

  1. 如果T是實體:需要提供一個接口/超類而不是T,如果子類之間的差異很大,那麼它只是一個空標記。

    @ManyToOne(targetEntity = T_EntityClass.class) @JoinColumn(name =「」) private T value;

  2. 如果它不是實體 - 看起來像你的情況: 創建抽象實體,其中包含除value字段外的所有字段,並從此實體的子實現中繼承,如String,Integer ....

    @Entity 
    @Inheritance(strategy = InheritanceType.JOINED) 
    public abstract class Attribute<T> { 
        @Id 
        @GeneratedValue(strategy = GenerationType.AUTO) 
        private Long id; 
    
        @ManyToOne 
        @JoinColumn(name = "item_id") 
        private Item item; 
    
        @Column 
        private String name; 
    
        @Column 
        boolean isTemplate; 
    
        public abstract T getValue(); 
    
        public abstract void setValue(T value); 
        ........ 
        } 
    

字符串實現:

@Entity 
public class AttributeStringValue extends Attribute<String>{ 

    @Column 
    String value; 

    @Override 
    public String getValue() { 
     return value; 
    } 

    @Override 
    public void setValue(String value) { 
     this.value = value; 
    } 
} 

整數實現:

@Entity 
public class AttributeIntegerValue extends Attribute<Integer>{ 

    @Column 
    Integer value; 

    @Override 
    public Integer getValue() { 
     return value; 
    } 

    @Override 
    public void setValue(Integer value) { 
     this.value = value; 
    } 
} 

的結果,你有3個表:

create table attribute (
    id bigint generated by default as identity, 
    is_template boolean, 
    name varchar(255), 
    item_id bigint, 
    primary key (id) 
) 

create table attribute_integer_value (
    value integer, 
    id bigint not null, 
    primary key (id) 
) 

create table attribute_string_value (
    value varchar(255), 
    id bigint not null, 
    primary key (id) 
) 
0

sbjavateam,謝謝你的詳細解釋。在我嘗試執行AttributeConverter之後,我得出了幾乎相同的結論。我堅持要將T value轉換爲String。它最終使用instance of來獲得對象類型,但我不能映射它的值。在你解釋的Also in relational databases you can't persist java object without appropriate type中有很好的解釋。

我結束了幾乎像你一樣的方法來創建額外的類包裝,但Attribute<T>真的是一個好主意....它帶給我阿森納證明design your entity first clean and nice and do mapping latter